diff options
-rw-r--r-- | ChangeLog | 48 | ||||
-rw-r--r-- | src/arch/arm/v7/arm.c | 121 | ||||
-rw-r--r-- | src/arch/arm/v7/helpers.c | 56 | ||||
-rw-r--r-- | src/arch/arm/v7/helpers.h | 4 | ||||
-rw-r--r-- | src/arch/arm/v7/opcodes/Makefile.am | 1 | ||||
-rw-r--r-- | src/arch/arm/v7/opdefs/Makefile.am | 4 | ||||
-rw-r--r-- | src/arch/arm/v7/opdefs/bl_A8825.d | 84 | ||||
-rwxr-xr-x | src/common/Makefile.am | 1 | ||||
-rw-r--r-- | src/common/asm.c | 67 | ||||
-rw-r--r-- | src/common/asm.h | 38 | ||||
-rw-r--r-- | tools/Makefile.am | 13 | ||||
-rw-r--r-- | tools/bits.c | 363 | ||||
-rw-r--r-- | tools/bits.h | 87 | ||||
-rw-r--r-- | tools/coder.c | 1306 | ||||
-rw-r--r-- | tools/coder.h | 53 | ||||
-rw-r--r-- | tools/conv.c | 1640 | ||||
-rw-r--r-- | tools/conv.h | 160 | ||||
-rw-r--r-- | tools/d2c_gram.y | 133 | ||||
-rw-r--r-- | tools/d2c_tok.l | 36 | ||||
-rw-r--r-- | tools/helpers.c | 144 | ||||
-rw-r--r-- | tools/helpers.h | 47 | ||||
-rw-r--r-- | tools/macros.c | 167 | ||||
-rw-r--r-- | tools/macros.h | 30 | ||||
-rw-r--r-- | tools/pproc.c | 214 | ||||
-rw-r--r-- | tools/pproc.h | 67 | ||||
-rw-r--r-- | tools/rules.c | 439 | ||||
-rw-r--r-- | tools/rules.h | 91 | ||||
-rw-r--r-- | tools/spec.c | 349 | ||||
-rw-r--r-- | tools/spec.h | 72 | ||||
-rw-r--r-- | tools/syntax.c | 321 | ||||
-rw-r--r-- | tools/syntax.h | 61 |
31 files changed, 4884 insertions, 1333 deletions
@@ -1,3 +1,51 @@ +14-11-14 Cyrille Bagard <nocbos@gmail.com> + + * src/arch/arm/v7/arm.c: + Support one more instructions category (§ A5.5). + + * src/arch/arm/v7/helpers.c: + * src/arch/arm/v7/helpers.h: + Load sign extended operands from raw values. + + * src/arch/arm/v7/opcodes/Makefile.am: + Add the 'bl.d' file to libarcharmv7opcodes_la_SOURCES. + + * src/arch/arm/v7/opdefs/bl_A8825.d: + New entries: define basic definition for bl/blx instructions. + + * src/arch/arm/v7/opdefs/Makefile.am: + Add a new macro 'SignExtend' to D2C_MACROS and bl_A8825.d to ARMV7_DEFS. + + * src/common/asm.c: + * src/common/asm.h: + New entries: compute the position of the first bit set in a 32b word. + + * src/common/Makefile.am: + Add the 'asm.[ch]' files to libcommon_la_SOURCES. + + * tools/bits.c: + * tools/bits.h: + * tools/coder.c: + * tools/coder.h: + * tools/conv.c: + * tools/conv.h: + * tools/d2c_gram.y: + * tools/d2c_tok.l: + * tools/helpers.c: + * tools/helpers.h: + * tools/macros.c: + * tools/macros.h: + * tools/Makefile.am: + * tools/pproc.c: + * tools/pproc.h: + * tools/rules.c: + * tools/rules.h: + * tools/spec.c: + * tools/spec.h: + * tools/syntax.c: + * tools/syntax.h: + Rewrite and extend the whole code for the instructions definitions compiler. + 14-11-01 Cyrille Bagard <nocbos@gmail.com> * src/arch/instruction.c: diff --git a/src/arch/arm/v7/arm.c b/src/arch/arm/v7/arm.c index 5295ef8..b7d4ff1 100644 --- a/src/arch/arm/v7/arm.c +++ b/src/arch/arm/v7/arm.c @@ -39,6 +39,8 @@ static GArchInstruction *process_armv7_data_processing_and_miscellaneous_instruc /* Désassemble une instruction ARMv7 de données de registre. */ static GArchInstruction *process_armv7_data_processing_register(uint32_t); +/* Désassemble une instruction ARMv7 de données ou autre. */ +static GArchInstruction *process_armv7_branch_branch_with_link_and_block_data_transfer(uint32_t); @@ -47,7 +49,7 @@ static GArchInstruction *process_armv7_data_processing_register(uint32_t); #define process_armv7_load_store_word_and_unsigned_byte(raw) NULL #define process_armv7_load_store_word_and_unsigned_byte(raw) NULL #define process_armv7_media_instructions(raw) NULL -#define process_armv7_branch_branch_with_link_and_block_data_transfer(raw) NULL +//#define process_armv7_branch_branch_with_link_and_block_data_transfer(raw) NULL #define process_armv7_coprocessor_instructions_and_Supervisor_call(raw) NULL #define process_armv7_unconditional_instructions(raw) NULL @@ -93,6 +95,26 @@ static GArchInstruction *process_armv7_data_processing_register(uint32_t); #define armv7_read_instr_mvn_register(raw) NULL +// process_armv7_branch_branch_with_link_and_block_data_transfer + +#define armv7_read_instr_stmda_stmed(raw) NULL +#define armv7_read_instr_ldmda_ldmfa(raw) NULL +#define armv7_read_instr_stm_stmia_stmea(raw) NULL +#define armv7_read_instr_ldm_ldmia_ldmfd_arm(raw) NULL +#define armv7_read_instr_ldm_ldmia_ldmfd_arm(raw) NULL +#define armv7_read_instr_pop_arm(raw) NULL +#define armv7_read_instr_stmdb_stmfd(raw) NULL +#define armv7_read_instr_stmdb_stmfd(raw) NULL +#define armv7_read_instr_push(raw) NULL +#define armv7_read_instr_ldmdb_ldmea(raw) NULL +#define armv7_read_instr_stmib_stmfa(raw) NULL +#define armv7_read_instr_ldmib_ldmed(raw) NULL +#define armv7_read_instr_stm_user_registers(raw) NULL +#define armv7_read_instr_ldm_user_registers(raw) NULL +#define armv7_read_instr_ldm_exception_return(raw) NULL +#define armv7_read_instr_b(raw) NULL +//#define armv7_read_instr_bl_blx_immediate(raw) NULL + @@ -127,7 +149,6 @@ GArchInstruction *process_armv7_instruction_set_encoding(uint32_t raw) op1 = (raw >> 25) & 0x7; op = (raw >> 4) & 0x1; - if (cond != b1111) { if ((op1 & b110) == b000) @@ -403,3 +424,99 @@ static GArchInstruction *process_armv7_data_processing_register(uint32_t raw) + + + + + + +/****************************************************************************** +* * +* Paramètres : raw = donnée brute de 32 bits à désassembler. * +* * +* Description : Désassemble une instruction ARMv7 de données ou autre. * +* * +* Retour : Instruction mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GArchInstruction *process_armv7_branch_branch_with_link_and_block_data_transfer(uint32_t raw) +{ + GArchInstruction *result; /* Instruction à retourner */ + uint32_t op; /* Champ 'op' à retrouver */ + uint32_t rn; /* Champ 'rn' à retrouver */ + uint32_t r; /* Champ 'r' à retrouver */ + + /** + * Suit les directives de : + * § A5.5 Branch, branch with link, and block data transferr + */ + + result = NULL; + + op = (raw >> 20) & 0x3f; + rn = (raw >> 16) & 0xf; + r = (raw >> 15) & 0x1; + + if ((op & b111101) == b000000) + result = armv7_read_instr_stmda_stmed(raw); + + else if ((op & b111101) == b000001) + result = armv7_read_instr_ldmda_ldmfa(raw); + + else if ((op & b111101) == b001000) + result = armv7_read_instr_stm_stmia_stmea(raw); + + else if (op == b001001) + result = armv7_read_instr_ldm_ldmia_ldmfd_arm(raw); + + else if (op == b001011) + { + if (rn != b1101) + result = armv7_read_instr_ldm_ldmia_ldmfd_arm(raw); + else /* if (rn == b1101) */ + result = armv7_read_instr_pop_arm(raw); + } + + else if (op == b010000) + result = armv7_read_instr_stmdb_stmfd(raw); + + else if (op == b010010) + { + if (rn != b1101) + result = armv7_read_instr_stmdb_stmfd(raw); + else /* if (rn == b1101) */ + result = armv7_read_instr_push(raw); + } + + else if ((op & b111101) == b010001) + result = armv7_read_instr_ldmdb_ldmea(raw); + + else if ((op & b111101) == b011000) + result = armv7_read_instr_stmib_stmfa(raw); + + else if ((op & b111101) == b011001) + result = armv7_read_instr_ldmib_ldmed(raw); + + else if ((op & b100101) == b000100) + result = armv7_read_instr_stm_user_registers(raw); + + else if ((op & b100101) == b000101) + { + if (r == b0) + result = armv7_read_instr_ldm_user_registers(raw); + else /* if (r == b1) */ + result = armv7_read_instr_ldm_exception_return(raw); + } + + else if ((op & b110000) == b100000) + result = armv7_read_instr_b(raw); + + else if ((op & b110000) == b110000) + result = armv7_read_instr_bl_blx_immediate(raw); + + return result; + +} diff --git a/src/arch/arm/v7/helpers.c b/src/arch/arm/v7/helpers.c index 632c1b7..e7c9ad8 100644 --- a/src/arch/arm/v7/helpers.c +++ b/src/arch/arm/v7/helpers.c @@ -26,11 +26,67 @@ #include "register.h" #include "../../register.h" +#include "../../immediate.h" +#include "../../../common/asm.h" /****************************************************************************** * * +* Paramètres : value = valeur sur 32 bits maximum à traiter. * +* topbit = valeur du bit de poids fort manipulé. * +* size = taille de la valeur finale à constituer. * +* * +* Description : Crée un opérande de valeur immédiate avec extension de signe.* +* * +* Retour : Adresse de la structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *sign_extend_armv7_imm(uint32_t value, bool topbit, unsigned int size) +{ + GArchOperand *result; /* Opérande à faire remonter */ + unsigned int msb; /* Position du premier bit à 1 */ + MemoryDataSize mds; /* Conversion de la taille */ + uint32_t val4; /* Valeur sur 4 bits */ + uint32_t val8; /* Valeur sur 8 bits */ + uint32_t val16; /* Valeur sur 16 bits */ + uint32_t val32; /* Valeur sur 32 bits */ + unsigned int i; /* Boucle de parcours */ + + result = NULL; + + topbit &= msb_32(value, &msb); + + switch (size) + { + +#define SIGN_EXTEND_CASE(sz) \ + case sz: \ + mds = MDS_ ## sz ## _BITS_SIGNED; \ + val ## sz = value; \ + if (topbit) \ + for (i = msb + 1; i < sz; i++) \ + val ## sz |= (1 << i); \ + result = g_imm_operand_new_from_value(mds, val ## sz); \ + break; + + SIGN_EXTEND_CASE(4); + SIGN_EXTEND_CASE(8); + SIGN_EXTEND_CASE(16); + SIGN_EXTEND_CASE(32); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : index = indice du registre correspondant. * * * * Description : Crée un opérande représentant un registre ARMv7. * diff --git a/src/arch/arm/v7/helpers.h b/src/arch/arm/v7/helpers.h index 9ea0d74..087b2e7 100644 --- a/src/arch/arm/v7/helpers.h +++ b/src/arch/arm/v7/helpers.h @@ -25,6 +25,7 @@ #define _ARCH_ARM_V7_HELPERS_H +#include <stdbool.h> #include <stdint.h> @@ -32,6 +33,9 @@ +/* Crée un opérande de valeur immédiate avec extension de signe. */ +GArchOperand *sign_extend_armv7_imm(uint32_t, bool, unsigned int); + /* Crée un opérande représentant un registre ARMv7. */ GArchOperand *translate_armv7_register(uint8_t); diff --git a/src/arch/arm/v7/opcodes/Makefile.am b/src/arch/arm/v7/opcodes/Makefile.am index e77b7e8..dc5c8d9 100644 --- a/src/arch/arm/v7/opcodes/Makefile.am +++ b/src/arch/arm/v7/opcodes/Makefile.am @@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libarcharmv7opcodes.la libarcharmv7opcodes_la_SOURCES = \ + bl.c \ mov.c \ subs.c diff --git a/src/arch/arm/v7/opdefs/Makefile.am b/src/arch/arm/v7/opdefs/Makefile.am index f2c5a35..9aa6a82 100644 --- a/src/arch/arm/v7/opdefs/Makefile.am +++ b/src/arch/arm/v7/opdefs/Makefile.am @@ -17,9 +17,11 @@ D2C_MACROS = \ -M SetFlags=g_armv7_instruction_define_setflags \ -M Condition=g_arm_instruction_set_cond \ -M Register=translate_armv7_register \ - -M "ExpandImmC32=g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, " + -M "ExpandImmC32=g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, " \ + -M SignExtend=sign_extend_armv7_imm ARMV7_DEFS = \ + bl_A8825.d \ mov_A88104.d \ subs_B9320.d diff --git a/src/arch/arm/v7/opdefs/bl_A8825.d b/src/arch/arm/v7/opdefs/bl_A8825.d new file mode 100644 index 0000000..c9ef5d0 --- /dev/null +++ b/src/arch/arm/v7/opdefs/bl_A8825.d @@ -0,0 +1,84 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * ##FILE## - traduction d'instructions ARMv7 + * + * Copyright (C) 2014 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/>. + */ + + +@title BL, BLX (immediate) + +@encoding(T1) { + + @word 1 1 1 1 0 S(1) imm10H(10) 1 1 J1(1) 1 J2(1) imm10L(10) H(1) + + @syntax <imm32> + + @conv { + + I1 = NOT(J1 EOR S) + I2 = NOT(J2 EOR S) + imm32 = SignExtend(S:I1:I2:imm10H:imm10L:'00', s, 32) + + } + +} + +@encoding(T2) { + + @word 1 1 1 1 0 S(1) imm10(10) 1 1 J1(1) 0 J2(1) imm11(11) + + @syntax <imm32> + + @conv { + + I1 = NOT(J1 EOR S) + I2 = NOT(J2 EOR S) + imm32 = SignExtend(S:I1:I2:imm10:imm11:'0', S, 32) + + } + +} + +@encoding(A1) { + + @word cond(4) 1 0 1 1 imm24(24) + + @syntax <imm32> + + @conv { + + imm32 = SignExtend(imm24:'00', 0, 32) + + } + +} + +@encoding(A2) { + + @word cond(4) 1 0 1 H(1) imm24(24) + + @syntax <imm32> + + @conv { + + imm32 = SignExtend(imm24:H:'0', 0, 32) + + } + +} diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 198de32..7615f43 100755 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -2,6 +2,7 @@ lib_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = \ + asm.h asm.c \ bconst.h \ cpp.h \ dllist.h dllist.c \ diff --git a/src/common/asm.c b/src/common/asm.c new file mode 100644 index 0000000..597013a --- /dev/null +++ b/src/common/asm.c @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * asm.c - implémentations génériques de fonctionnalités spécifiques + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "asm.h" + + + +/****************************************************************************** +* * +* Paramètres : v = valeur quelconque sur 32 bits. * +* p = position du premier bit à 1 (poids fort). [OUT] * +* * +* Description : Détermine l'indice du premier bit à 1, côté gauche. * +* * +* Retour : true si le nombre est différent de zéro, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool msb_32(uint32_t v, unsigned int *p) +{ + static const unsigned int bval[] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; + + /* S'il n'y a aucun bit à 1... */ + if (v == 0) return false; + + /** + * Il existe de nombreuses méthodes pour obtenir le résultat attendu + * sans recourir à des extensions GCC ou à des instructions d'assembleur : + * + * - http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array + * - http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious + * + */ + + *p = 0; + + if (v & 0xffff0000) { *p += 16 / 1; v >>= 16 / 1; } + if (v & 0x0000ff00) { *p += 16 / 2; v >>= 16 / 2; } + if (v & 0x000000f0) { *p += 16 / 4; v >>= 16 / 4; } + + *p += bval[v]; + + return true; + +} diff --git a/src/common/asm.h b/src/common/asm.h new file mode 100644 index 0000000..047d8db --- /dev/null +++ b/src/common/asm.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * asm.h - prototypes pour les implémentations génériques de fonctionnalités spécifiques + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _COMMON_ASM_H +#define _COMMON_ASM_H + + +#include <stdbool.h> +#include <stdint.h> + + + +/* Détermine l'indice du premier bit à 1, côté gauche. */ +bool msb_32(uint32_t, unsigned int *); + + + +#endif /* _COMMON_ASM_H */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 9a91f9d..d0fdbe8 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -7,13 +7,20 @@ bin_PROGRAMS = d2c d2c_SOURCES = \ + bits.h bits.c \ coder.h coder.c \ + conv.h conv.c \ + d2c_tok.l \ d2c_gram.y \ - d2c_tok.l + helpers.h helpers.c \ + pproc.h pproc.c \ + rules.h rules.c \ + spec.h spec.c \ + syntax.h syntax.c -d2c_YFLAGS = -d -p d2c_ -o y.tab.c +d2c_YFLAGS = -v -d -p d2c_ -o y.tab.c -d2c_LFLAGS = -P d2c_ -o lex.yy.c +d2c_LFLAGS = -P d2c_ --header-file=d2c_tok.h -o lex.yy.c AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) diff --git a/tools/bits.c b/tools/bits.c new file mode 100644 index 0000000..32c3fd9 --- /dev/null +++ b/tools/bits.c @@ -0,0 +1,363 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.c - compréhension et manipulation des champs de bits + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "bits.h" + + +#include <assert.h> +#include <inttypes.h> +#include <malloc.h> +#include <stdint.h> +#include <string.h> + + +#include "helpers.h" + + + + + +/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ + + +/* Elément d'un mot décodé */ +struct _raw_bitfield +{ + char *name; /* Désignation humaine */ + unsigned int start; /* Position de départ */ + unsigned int length; /* Taille du champ */ + + bool used; /* Champ défini & utilisé */ + +}; + + + + +/* Représentation de l'ensemble des bits de codage */ +struct _coding_bits +{ + raw_bitfield *fields; /* Champs de bits détectés */ + size_t bf_count; /* Nombre de ces champs */ + uint64_t bits; /* Bits invariables */ + uint64_t mask; /* Emplacement de ces bits */ + unsigned int curpos; /* Position pendant l'analyse */ + +}; + + + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : field = champ de bits à consulter. * +* * +* Description : Indique le nombre de bits utilisés par le champ. * +* * +* Retour : Nombre de bits considérés. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned int get_raw_bitfield_length(const raw_bitfield *field) +{ + return field->length; + +} + + +/****************************************************************************** +* * +* Paramètres : field = champ de bits à traiter. * +* * +* Description : Marque un champ de bits comme étant utile. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void mark_raw_bitfield_as_used(raw_bitfield *field) +{ + field->used = true; + +} + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau gestionnaire des bits d'encodage brut. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +coding_bits *create_coding_bits(void) +{ + coding_bits *result; /* Définition vierge à renvoyer*/ + + result = (coding_bits *)calloc(1, sizeof(coding_bits)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bits = gestionnaire d'un ensemble de bits à libérer. * +* * +* Description : Supprime de la mémoire un gestionnaire de bits d'encodage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_coding_bits(coding_bits *bits) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < bits->bf_count; i++) + free(bits->fields[i].name); + + if (bits->fields != NULL) + free(bits->fields); + + free(bits); + +} + + +/****************************************************************************** +* * +* Paramètres : bits = gestionnaire de bits d'encodage brut à consulter. * +* name = désignation humaine du champ remarqué. * +* length = taille du champ à mémoriser. * +* * +* Description : Note la présence d'un champ remarquable dans une définition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_named_field_in_bits(coding_bits *bits, char *name, unsigned int length) +{ + raw_bitfield *field; /* Nouveau champ à constituer */ + + assert((bits->curpos + length) < 64); + + bits->fields = (raw_bitfield *)realloc(bits->fields, + ++bits->bf_count * sizeof(raw_bitfield)); + + field = &bits->fields[bits->bf_count - 1]; + + field->name = make_string_lower(name); + field->start = bits->curpos; + field->length = length; + + bits->curpos += length; + +} + + +/****************************************************************************** +* * +* Paramètres : bits = gestionnaire de bits d'encodage brut à consulter. * +* val = valeur du bit à prendre en compte. * +* * +* Description : Note la présence d'un bit invariable dans une définition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_bit_in_bits(coding_bits *bits, int val) +{ + assert(bits->curpos < 64); + + bits->bits |= (val ? 1 : 0) << bits->curpos; + bits->mask |= 1 << bits->curpos; + + bits->curpos++; + +} + + +/****************************************************************************** +* * +* Paramètres : bits = gestionnaire de bits d'encodage brut à consulter. * +* * +* Description : Indique le nombre de bits traités. * +* * +* Retour : Quantité, positive ou nulle. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned int count_coded_bits(const coding_bits *bits) +{ + return bits->curpos; + +} + + +/****************************************************************************** +* * +* Paramètres : bits = gestionnaire d'encodage brut à consulter. * +* name = désignation humaine du champ à retrouver. * +* * +* Description : Recherche un champ donné dans un ensemble de champs de bits. * +* * +* Retour : Structure associée au champ trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +raw_bitfield *find_named_field_in_bits(const coding_bits *bits, const char *name) +{ + raw_bitfield *result; /* Champ de bits à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < bits->bf_count && result == NULL; i++) + if (strcmp(bits->fields[i].name, name) == 0) + result = &bits->fields[i]; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification servant de base à l'opération. * +* fd = descripteur d'un flux ouvert en écriture. * +* wide = taille des mots manipulés (en bits). * +* * +* Description : Déclare les variables C associées aux champs de bits. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool declare_used_bits_fields(const coding_bits *bits, int fd, unsigned int wide) +{ + size_t i; /* Boucle de parcours */ + + 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); + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification servant de base à l'opération. * +* fd = descripteur d'un flux ouvert en écriture. * +* * +* Description : Vérifie que les bits fixes correspondent au masque attendu. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool check_bits_correctness(const coding_bits *bits, int fd) +{ + dprintf(fd, "\t\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n", bits->mask, bits->bits); + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification servant de base à l'opération. * +* fd = descripteur d'un flux ouvert en écriture. * +* * +* Description : Définit les variables C associées aux champs de bits. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_used_bits_fields(const coding_bits *bits, int fd) +{ + size_t i; /* Boucle de parcours */ + raw_bitfield *rf; /* Accès confortable à un champ*/ + + for (i = 0; i < bits->bf_count; i++) + { + 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); + + } + + return true; + +} diff --git a/tools/bits.h b/tools/bits.h new file mode 100644 index 0000000..aa4b7aa --- /dev/null +++ b/tools/bits.h @@ -0,0 +1,87 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.h - prototypes pour la compréhension et la manipulation des champs de bits + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_BITS_H +#define _TOOLS_BITS_H + + +#include <stdbool.h> + + + + +/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ + + +/* Elément d'un mot décodé */ +typedef struct _raw_bitfield raw_bitfield; + + + +/* Indique le nombre de bits utilisés par le champ. */ +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 *); + + + + + +/* Représentation de l'ensemble des bits de codage */ +typedef struct _coding_bits coding_bits; + + + +/* Crée un nouveau gestionnaire des bits d'encodage brut. */ +coding_bits *create_coding_bits(void); + +/* Supprime de la mémoire un gestionnaire de bits d'encodage. */ +void delete_coding_bits(coding_bits *); + + + +/* Note la présence d'un champ remarquable dans une définition. */ +void register_named_field_in_bits(coding_bits *, char *, unsigned int); + +/* Note la présence d'un bit invariable dans une définition. */ +void register_bit_in_bits(coding_bits *, int); + +/* Indique le nombre de bits traités. */ +unsigned int count_coded_bits(const coding_bits *); + +/* Recherche un champ donné dans un ensemble de champs de 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); + +/* Vérifie que les bits fixes correspondent au masque attendu. */ +bool check_bits_correctness(const coding_bits *, int); + +/* Définit les variables C associées aux champs de bits. */ +bool define_used_bits_fields(const coding_bits *, int); + + + +#endif /* _TOOLS_BITS_H */ diff --git a/tools/coder.c b/tools/coder.c index 3606bea..5856d80 100644 --- a/tools/coder.c +++ b/tools/coder.c @@ -25,32 +25,23 @@ #include <assert.h> -#include <ctype.h> #include <fcntl.h> -#include <inttypes.h> #include <malloc.h> #include <regex.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <unistd.h> -#include <sys/param.h> +#include "helpers.h" -/* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ -/* Conversion des chaînes en chaînes */ -typedef struct _string_exch -{ - const char *src; /* Chaîne à trouver */ - const char *dest; /* Chaîne de remplacement */ +/* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ -} string_exch; -struct _encoding_spec; /* Suivi des constructions */ @@ -60,89 +51,24 @@ struct _rented_coder const char *arch; /* Architecture à traiter */ const char *header; /* En-tête pour les en-têtes */ - string_exch *macros; /* Remplacements de chaînes */ - size_t macros_count; /* Nombre de ces remplacements */ - - string_exch *encodings; /* Traductions d'encodages */ - size_t encodings_count; /* Nombre de ces traductions */ + pre_processor *pp; /* Pré-processeur avec macros */ char *copyright; /* Récupération des droits */ char *ins; /* Désignation humaine */ char *details; /* Eventuels compléments */ - struct _encoding_spec *specs; /* Définitions déjà en place */ + encoding_spec **specs; /* Définitions déjà en place */ size_t specs_count; /* Nombre de ces définitions */ - struct _encoding_spec *cur_spec; /* Définition courante */ + encoding_spec *cur_spec; /* Définition courante */ }; -/* Recherche l'existence d'une macro pour un remplacement. */ -static const char *find_macro_in_coder(const rented_coder *, const char *); - /* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ -struct _dec_bitfield; -struct _syntax_item; -struct _conv_func; -struct _extra_rule; - - -/* Mémorisation d'un encodage complet */ -typedef struct _encoding_spec -{ - char *prefix; /* Distinction principale */ - unsigned int index; /* Distinction secondaire */ - - struct _dec_bitfield *bitfields; /* Champs de bits détectés */ - size_t bf_count; /* Nombre de ces champs */ - uint64_t bits; /* Bits invariables */ - uint64_t mask; /* Emplacement de ces bits */ - unsigned int curpos; /* Position pendant l'analyse */ - - struct _syntax_item *items; /* Eléments de la syntaxe */ - size_t items_count; /* Nombre de ces éléments */ - - struct _conv_func *conversions; /* Conversions des données */ - size_t conv_count; /* Nombre de ces conversions */ - - struct _extra_rule *rules; /* Régles supplémentaires */ - size_t rules_count; /* Nombre de ces règles */ - -} encoding_spec; - - -/* Libère de la mémoire une spécification d'encodage. */ -static void free_encoding_spec(encoding_spec *); - - - -/* ---------------------------- SYNTAXE DES INSTRUCTIONS ---------------------------- */ - - -/* Propriétés particulières pour les opérandes */ -typedef enum _SyntaxItemFlags -{ - SIF_NONE = (0 << 0), /* Aucune propriété */ - SIF_DECIMAL = (1 << 0) /* Affichage en décimal */ - -} SyntaxItemFlags; - -/* Elément défini dans une syntaxe */ -typedef struct _syntax_item -{ - char *name; /* Désignation humaine */ - bool internal; /* Enregistrement générique ? */ - SyntaxItemFlags flags; /* Propriétés supplémentaires */ - -} syntax_item; - - -/* Libère de la mémoire tous les éléments de syntaxe. */ -static void free_all_syntax_items_in_spec(encoding_spec *); @@ -161,11 +87,6 @@ typedef struct _dec_bitfield -/* Recherche un champ donné dans une définition. */ -static const dec_bitfield *find_named_field_in_spec(const encoding_spec *, const char *); - -/* Libère de la mémoire toutes les champs de bits définis. */ -static void free_all_bitfields_in_spec(encoding_spec *); @@ -182,67 +103,6 @@ typedef struct _conv_func } conv_func; -/* Libère de la mémoire toutes les conversions enregistrées. */ -static void free_all_conversion_in_spec(encoding_spec *); - -/* Recherche une fonction converrtissant une donnée brute. */ -static const conv_func *find_conversion_in_coder_spec(const encoding_spec *, const char *); - - - -/* --------------------------- CONDITIONS ET CONSEQUENCES --------------------------- */ - - -/* Expression d'une condition */ -struct _cond_expr -{ - bool is_simple; /* Sélection de champ */ - - union - { - struct - { - char *variable; /* Variable manipulée */ - CondCompType comp; /* Type de comparaison */ - char *bvalue; /* Valeur binaire comparée */ - - } simple; - - struct - { - cond_expr *a; /* Première sous-expression */ - CondOpType operator; /* Relation entre expressions */ - cond_expr *b; /* Seconde sous-expression */ - - } composed; - - }; - -}; - -/* Règles particulières */ -typedef struct _extra_rule -{ - cond_expr *expr; /* Expression de déclenchement */ - CondActionType action; /* Conséquence d'une validation*/ - char *details; /* Eventuel complément d'info. */ - -} extra_rule; - - -/* Libère de la mémoire une expression conditionnelle. */ -static void free_cond_expr(cond_expr *); - -/* Traduit en code une expression de condition. */ -static bool write_cond_expr(const encoding_spec *, int, const cond_expr *); - -/* Libère de la mémoire des règles. */ -static void free_all_coder_spec_rules(encoding_spec *); - -/* Traduit en code les éventuelles règles présentes. */ -static bool write_coder_spec_rules(const rented_coder *, int, const encoding_spec *, bool *); - - /* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ @@ -253,23 +113,6 @@ static int create_code_file(const rented_coder *, const char *, const char *, co /* 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); -/* Traduit en code une sous-fonction de désassemblage. */ -static bool write_coder_spec_disass(const rented_coder *, int, const encoding_spec *, const char *, unsigned int); - - - -/* ---------------------------- MANIPULATIONS DE CHAINES ---------------------------- */ - - -/* Bascule toute une chaîne de caractères en (min|maj)uscules. */ -static char *_make_string_xxx(char *, int (* fn) (int)); - -#define make_string_lower(str) _make_string_xxx(str, tolower) -#define make_string_upper(str) _make_string_xxx(str, toupper) - -/* Traduit une chaîne en élément de fonction C. */ -static char *make_callable(const char *raw, bool); - /* ---------------------------------------------------------------------------------- */ @@ -295,7 +138,9 @@ rented_coder *create_coder(void) result = (rented_coder *)calloc(1, sizeof(rented_coder)); - result->cur_spec = (encoding_spec *)calloc(1, sizeof(encoding_spec)); + result->pp = create_pre_processor(); + + result->cur_spec = create_encoding_spec(); return result; @@ -318,11 +163,7 @@ void delete_coder(rented_coder *coder) { size_t i; /* Boucle de parcours */ - if (coder->macros != NULL) - free(coder->macros); - - if (coder->encodings != NULL) - free(coder->encodings); + delete_pre_processor(coder->pp); if (coder->ins != NULL) free(coder->ins); @@ -331,14 +172,12 @@ void delete_coder(rented_coder *coder) free(coder->details); for (i = 0; i < coder->specs_count; i++) - free_encoding_spec(&coder->specs[i]); + delete_encoding_spec(coder->specs[i]); if (coder->specs != NULL) free(coder->specs); - free_encoding_spec(coder->cur_spec); - - free(coder->cur_spec); + delete_encoding_spec(coder->cur_spec); free(coder); @@ -427,84 +266,18 @@ void set_coder_header_base(rented_coder *coder, const char *header) /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* src = chaîne à remplacer dans les définitions. * -* dest = chaîne de remplacement. * * * -* Description : Enregistre une correspondance en matière d'encodage. * +* Description : Fournit le pré-processeur du compilateur. * * * -* Retour : - * +* Retour : Pré-processeur à manipuler. * * * * Remarques : - * * * ******************************************************************************/ -void register_encoding_in_coder(rented_coder *coder, const char *src, const char *dest) +pre_processor *get_coder_pre_proc(const rented_coder *coder) { - string_exch *encoding; /* Traduction à conserver */ - - coder->encodings = (string_exch *)realloc(coder->encodings, ++coder->encodings_count * sizeof(string_exch)); - - encoding = &coder->encodings[coder->encodings_count - 1]; - - encoding->src = src; - encoding->dest = dest; - -} - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* src = chaîne à remplacer dans les définitions. * -* dest = chaîne de remplacement. * -* * -* Description : Constitue la matière d'un système de macros. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void define_macro_for_coder(rented_coder *coder, const char *src, const char *dest) -{ - string_exch *macro; /* Nouvelle macro à constituer */ - - coder->macros = (string_exch *)realloc(coder->macros, ++coder->macros_count * sizeof(string_exch)); - - macro = &coder->macros[coder->macros_count - 1]; - - macro->src = src; - macro->dest = dest; - -} - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* src = chaîne à remplacer dans les définitions. * -* * -* Description : Recherche l'existence d'une macro pour un remplacement. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static const char *find_macro_in_coder(const rented_coder *coder, const char *src) -{ - const char *result; /* Trouvaille à renvoyer */ - size_t i; /* Boucle de parcours */ - - result = NULL; - - for (i = 0; i < coder->macros_count && result == NULL; i++) - if (strcmp(coder->macros[i].src, src) == 0) - result = coder->macros[i].dest; - - return result; + return coder->pp; } @@ -542,599 +315,29 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, const char /****************************************************************************** * * * Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* prefix = distinction principale entre les définitions. * -* index = distinction secondaire entre les définitions. * -* * -* Description : Enregistre une définition supplémentaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index) -{ - encoding_spec *spec; /* Définition à compléter */ - - spec = coder->cur_spec; - - spec->prefix = prefix; - spec->index = index; - - coder->specs = (encoding_spec *)realloc(coder->specs, ++coder->specs_count * sizeof(encoding_spec)); - - coder->specs[coder->specs_count - 1] = *spec; - - memset(spec, 0, sizeof(encoding_spec)); - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'encodage en cours de libération. * -* * -* Description : Libère de la mémoire une spécification d'encodage. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void free_encoding_spec(encoding_spec *spec) -{ - free_all_syntax_items_in_spec(spec); - - free_all_bitfields_in_spec(spec); - - free_all_conversion_in_spec(spec); - - free_all_coder_spec_rules(spec); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* GESTION DES CHAMPS DE BITS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* name = désignation humaine du champ remarqué. * -* length = taille du champ à mémoriser. * -* * -* Description : Note la présence d'un champ remarquable dans une définition. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void register_named_field_in_coder(rented_coder *coder, char *name, unsigned int length) -{ - encoding_spec *spec; /* Définition à compléter */ - dec_bitfield *field; /* Nouveau champ à constituer */ - - spec = coder->cur_spec; - - assert((spec->curpos + length) < 64); - - spec->bitfields = (dec_bitfield *)realloc(spec->bitfields, - ++spec->bf_count * sizeof(dec_bitfield)); - - field = &spec->bitfields[spec->bf_count - 1]; - - field->name = make_string_lower(name); - field->start = spec->curpos; - field->length = length; - - spec->curpos += length; - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'encodage à parcourir. * -* name = désignation humaine du champ à retrouver. * -* * -* Description : Recherche un champ donné dans une définition. * -* * -* Retour : Structure associée au champ trouvé ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static const dec_bitfield *find_named_field_in_spec(const encoding_spec *spec, const char *name) -{ - dec_bitfield *result; /* Champ de bits à retourner */ - size_t i; /* Boucle de parcours */ - - result = NULL; - - for (i = 0; i < spec->bf_count && result == NULL; i++) - if (strcmp(spec->bitfields[i].name, name) == 0) - result = &spec->bitfields[i]; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* val = valeur du bit à prendre en compte. * -* * -* Description : Note la présence d'un bit invariable dans une définition. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void register_bit_in_coder(rented_coder *coder, int val) -{ - encoding_spec *spec; /* Définition à compléter */ - - spec = coder->cur_spec; - - assert(spec->curpos < 64); - - spec->bits |= (val ? 1 : 0) << spec->curpos; - spec->mask |= 1 << spec->curpos; - - spec->curpos++; - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'encodage en cours de libération. * -* * -* Description : Libère de la mémoire toutes les champs de bits définis. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void free_all_bitfields_in_spec(encoding_spec *spec) -{ - size_t i; /* Boucle de parcours */ - - for (i = 0; i < spec->bf_count; i++) - free(spec->bitfields[i].name); - - if (spec->bitfields != NULL) - { - free(spec->bitfields); - spec->bitfields = NULL; - } - - spec->bf_count = 0; - - spec->bits = 0; - spec->mask = 0; - - spec->curpos = 0; - -} - - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* * -* Description : Indique le nombre de bits traités. * -* * -* Retour : Quantité, positive ou nulle. * -* * -* Remarques : - * -* * -******************************************************************************/ - -unsigned int count_coder_bits(const rented_coder *coder) -{ - return coder->cur_spec->curpos; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* SYNTAXE DES INSTRUCTIONS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement d'humain. * -* name = désignation de l'opérande dans la spécification. * -* internal = précise si l'opérand est non générique ou non. * -* * -* Description : Enregistre la présence d'un nouvel opérande. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void register_syntax_item_in_coder(rented_coder *coder, char *name, bool internal) -{ - encoding_spec *spec; /* Définition à compléter */ - syntax_item *item; /* Nouvelle prise en compte */ - size_t len; /* Taille du nom fourni */ - - spec = coder->cur_spec; - - spec->items = (syntax_item *)realloc(spec->items, ++spec->items_count * sizeof(syntax_item)); - - item = &spec->items[spec->items_count - 1]; - - /* Récupération des drapeaux */ - - item->flags = SIF_NONE; - - for (len = strlen(name); len > 0; len--) - switch (name[0]) - { - case '#': - item->flags |= SIF_DECIMAL; - memmove(name, name + 1, len); - break; - - default: - len = 1; - break; - - } - - item->name = make_string_lower(name); - item->internal = internal; - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'encodage en cours de libération. * -* * -* Description : Libère de la mémoire tous les éléments de syntaxe. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void free_all_syntax_items_in_spec(encoding_spec *spec) -{ - size_t i; /* Boucle de parcours */ - - for (i = 0; i < spec->items_count; i++) - free(spec->items[i].name); - - if (spec->items != NULL) - { - free(spec->items); - spec->items = NULL; - } - - spec->items_count = 0; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* CONVERSION DES ARGUMENTS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* dest = désignation de la variable de destination. * -* func = nom de la fonction assurant le calcul de valeur. * -* arg = argument à fournir à cette fonction. * -* * -* Description : Enregistre la function de conversion du brut à l'utile. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void register_conversion_in_coder(rented_coder *coder, char *dest, char *func, char *arg) -{ - encoding_spec *spec; /* Définition à compléter */ - conv_func *conv; /* Nouvelle prise en compte */ - - spec = coder->cur_spec; - - spec->conversions = (conv_func *)realloc(spec->conversions, ++spec->conv_count * sizeof(conv_func)); - - conv = &spec->conversions[spec->conv_count - 1]; - - conv->dest = make_string_lower(dest); - conv->func = func; - conv->arg = make_string_lower(arg); - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'encodage en cours de libération. * -* * -* Description : Libère de la mémoire toutes les conversions enregistrées. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void free_all_conversion_in_spec(encoding_spec *spec) -{ - size_t i; /* Boucle de parcours */ - conv_func *conv; /* Conversion à traiter */ - - for (i = 0; i < spec->conv_count; i++) - { - conv = &spec->conversions[i]; - - free(conv->dest); - free(conv->func); - free(conv->arg); - - } - - if (spec->conversions != NULL) - { - free(spec->conversions); - spec->conversions = NULL; - } - - spec->conv_count = 0; - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'un encodage à consulter. * -* dest = désignation d'une variable de destination. * -* * -* Description : Recherche une fonction converrtissant une donnée brute. * -* * -* Retour : Structure de conversion trouvée ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static const conv_func *find_conversion_in_coder_spec(const encoding_spec *spec, const char *dest) -{ - const conv_func *result; /* Conversion à renvoyer */ - size_t i; /* Boucle de parcours */ - - result = NULL; - - for (i = 0; i < spec->conv_count && result == NULL; i++) - if (strcmp(spec->conversions[i].dest, dest) == 0) - result = &spec->conversions[i]; - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* CONDITIONS ET CONSEQUENCES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : variable = désignation de la variable à manipuler. * -* comp = type de comparaison à utiliser. * -* bvalue = valeur binaire à comparer. * -* * -* Description : Crée une expression conditionnelle simple. * -* * -* Retour : Structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -cond_expr *build_simple_cond_expression(char *variable, CondCompType comp, char *bvalue) -{ - cond_expr *result; /* Structure à retourner */ - - result = (cond_expr *)calloc(1, sizeof(cond_expr)); - - result->is_simple = true; - - result->simple.variable = make_string_lower(variable); - result->simple.comp = comp; - result->simple.bvalue = bvalue; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : a = première expression à intégrer. * -* operator = type de comparaison à utiliser. * -* b = second expression à intégrer. * * * -* Description : Crée une expression conditionnelle composée. * +* Description : Fournit un lien vers les spécifications courantes. * * * -* Retour : Structure mise en place. * +* Retour : Spécification en cours d'édition. * * * * Remarques : - * * * ******************************************************************************/ -cond_expr *build_composed_cond_expression(cond_expr *a, CondOpType operator, cond_expr *b) +encoding_spec *get_current_encoding_spec(const rented_coder *coder) { - cond_expr *result; /* Structure à retourner */ - - result = (cond_expr *)calloc(1, sizeof(cond_expr)); - - result->is_simple = false; - - result->composed.a = a; - result->composed.operator = operator; - result->composed.b = b; - - return result; + return coder->cur_spec; } /****************************************************************************** * * -* Paramètres : expr = représentation d'expression à traiter. * -* * -* Description : Libère de la mémoire une expression conditionnelle. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void free_cond_expr(cond_expr *expr) -{ - if (expr->is_simple) - { - free(expr->simple.variable); - free(expr->simple.bvalue); - } - else - { - free_cond_expr(expr->composed.a); - free_cond_expr(expr->composed.b); - } - - free(expr); - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'un encodage à consulter. * -* fd = descripteur d'un flux ouvert en écriture. * -* expr = expression simple ou composée à transposer. * -* * -* Description : Traduit en code une expression de condition. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool write_cond_expr(const encoding_spec *spec, int fd, const cond_expr *expr) -{ - bool result; /* Bilan à renvoyer */ - const dec_bitfield *bf; /* Champ de bits de définition */ - - result = true; - - dprintf(fd, "("); - - if (expr->is_simple) - { - bf = find_named_field_in_spec(spec, expr->simple.variable); - if (bf == NULL) - { - fprintf(stderr, "Error: no bitfield defined the requested variable '%s'.\n", expr->simple.variable); - result = false; - goto wce_exit; - } - - if (bf->length != strlen(expr->simple.bvalue)) - { - fprintf(stderr, "Error: variable '%s' and provided value sizes do not match (%u vs %zu).\n", - expr->simple.variable, bf->length, strlen(expr->simple.bvalue)); - result = false; - goto wce_exit; - } - - dprintf(fd, "raw_%s", expr->simple.variable); - - switch (expr->simple.comp) - { - case CCT_EQUAL: - dprintf(fd, " == "); - break; - case CCT_DIFF: - dprintf(fd, " != "); - break; - } - - dprintf(fd, "b%s", expr->simple.bvalue); - - } - else - { - result = write_cond_expr(spec, fd, expr->composed.a); - if (!result) goto wce_exit; - - switch (expr->composed.operator) - { - case COT_AND: - dprintf(fd, " && "); - break; - case COT_OR: - dprintf(fd, " || "); - break; - } - - result = write_cond_expr(spec, fd, expr->composed.b); - if (!result) goto wce_exit; - - } - - dprintf(fd, ")"); - - wce_exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain.* -* expr = représentation d'expression à conserver. * -* action = conséquence associée à la règle. * -* details = éventuel complément d'informations. * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* prefix = distinction principale entre les définitions. * +* index = distinction secondaire entre les définitions. * * * -* Description : Ajoute une règle complète à la définition d'un codage. * +* Description : Enregistre une définition supplémentaire. * * * * Retour : - * * * @@ -1142,129 +345,18 @@ static bool write_cond_expr(const encoding_spec *spec, int fd, const cond_expr * * * ******************************************************************************/ -void add_conditional_rule_to_coder(rented_coder *coder, cond_expr *expr, CondActionType action, const char *details) +void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index) { encoding_spec *spec; /* Définition à compléter */ - extra_rule *rule; /* Nouvelle prise en compte */ spec = coder->cur_spec; - spec->rules = (extra_rule *)realloc(spec->rules, ++spec->rules_count * sizeof(extra_rule)); + define_encoding_spec_code_name(spec, prefix, index); - rule = &spec->rules[spec->rules_count - 1]; + coder->specs = (encoding_spec **)realloc(coder->specs, ++coder->specs_count * sizeof(encoding_spec *)); + coder->specs[coder->specs_count - 1] = spec; - rule->expr = expr; - rule->action = action; - rule->details = make_callable(details, false); - -} - - -/****************************************************************************** -* * -* Paramètres : spec = spécification d'encodage à traiter. * -* * -* Description : Libère de la mémoire des règles. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void free_all_coder_spec_rules(encoding_spec *spec) -{ - size_t i; /* Boucle de parcours */ - - for (i = 0; i < spec->rules_count; i++) - { - free_cond_expr(spec->rules[i].expr); - - if (spec->rules[i].details) - free(spec->rules[i].details); - - } - - if (spec->rules != NULL) - { - free(spec->rules); - spec->rules = NULL; - } - - spec->rules_count = 0; - -} - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain. * -* fd = descripteur d'un flux ouvert en écriture. * -* spec = spécification servant de base à l'opération. * -* exit = exprime le besoin d'une voie de sortie. [OUT] * -* * -* Description : Traduit en code les éventuelles règles présentes. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool write_coder_spec_rules(const rented_coder *coder, int fd, const encoding_spec *spec, bool *exit) -{ - bool result; /* Bilan à remonter */ - const extra_rule *rule; /* Règle en cours d'écriture */ - size_t i; /* Boucle de parcours */ - - result = true; - - *exit = false; - - for (i = 0; i < spec->rules_count; i++) - { - rule = &spec->rules[i]; - - dprintf(fd, "\t\tif "); - - result = write_cond_expr(spec, fd, rule->expr); - if (!result) break; - - dprintf(fd, "\n"); - dprintf(fd, "\t\t{\n"); - - switch (rule->action) - { - case CAT_SEE: - - if (rule->details == NULL) - { - fprintf(stderr, "Error: directive 'see' must provide additional details.\n"); - result = false; - goto wcsr_exit; - } - - dprintf(fd, "\t\t\tinstr = armv7_read_instr_%s", rule->details); - - /* TODO : adapter les paramètres d'appel selon le 'coder' */ - dprintf(fd, "(_raw);\n"); - - dprintf(fd, "\t\t\tgoto quick_exit;\n"); - - *exit = true; - break; - - } - - dprintf(fd, "\t\t}\n"); - - dprintf(fd, "\n"); - - } - - wcsr_exit: - - return result; + coder->cur_spec = create_encoding_spec(); } @@ -1360,7 +452,7 @@ bool dump_all_routines_using_coder(const rented_coder *coder) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ - string_exch *encoding; /* Type d'encodage visé */ + const string_exch *encoding; /* Type d'encodage visé */ bool exist; /* Présence du fichier visé ? */ int header_fd; /* Fichier de déclarations */ char *dash; /* Présence d'un tiret ? */ @@ -1369,9 +461,9 @@ bool dump_all_routines_using_coder(const rented_coder *coder) result = true; - for (i = 0; i < coder->encodings_count && result; i++) + for (i = 0; i < count_encodings(coder->pp) && result; i++) { - encoding = &coder->encodings[i]; + encoding = find_encoding(coder->pp, i); /* Fichier de déclarations */ @@ -1462,6 +554,7 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st unsigned int wide; /* Taille des mots */ size_t i; /* Boucle de parcours */ encoding_spec *spec; /* Définition à traiter */ + coding_bits *bits; /* Gestionnaire de bits */ size_t maxlen; /* Taille à compléter */ result = true; @@ -1474,12 +567,13 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st for (i = 0; i < coder->specs_count; i++) { - spec = &coder->specs[i]; + spec = coder->specs[i]; - if (strcmp(encoding->src, spec->prefix) != 0) + if (!has_encoding_spec_prefix(spec, encoding->src)) continue; - wide = spec->curpos; + bits = get_bits_in_encoding_spec(spec); + wide = count_coded_bits(bits); break; } @@ -1532,12 +626,12 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st for (i = 0; i < coder->specs_count && result; i++) { - spec = &coder->specs[i]; + spec = coder->specs[i]; - if (strcmp(encoding->src, spec->prefix) != 0) + if (!has_encoding_spec_prefix(spec, encoding->src)) continue; - result = write_coder_spec_disass(coder, cfd, spec, keyword, wide); + result = write_encoding_spec_disass(spec, cfd, coder->arch, coder->ins, coder->details, wide, coder->pp); } @@ -1554,325 +648,3 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st return result; } - - -/****************************************************************************** -* * -* Paramètres : coder = gestion par la machine en remplacement de l'humain.* -* fd = descripteur d'un flux ouvert en écriture. * -* spec = spécification servant de base à l'opération. * -* keyword = nom clef de l'instruction utilisable dans du code. * -* wide = taille des mots manipulés (en bits). * -* * -* Description : Traduit en code une sous-fonction de désassemblage. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool write_coder_spec_disass(const rented_coder *coder, int fd, const encoding_spec *spec, const char *keyword, unsigned int wide) -{ - size_t i; /* Boucle de parcours */ - dec_bitfield *bf; /* Accès confortable à un champ*/ - bool exit; /* Inclusion de sortie rapide ?*/ - syntax_item *item; /* Lien vers un opérande */ - regex_t preg; /* Expression régulière */ - int ret; /* Bilan d'une manipulation */ - const conv_func *conv; /* Moyen de conversion du brut */ - const char *callable; /* Fonction à appeler */ - bool rebuild; /* Construction complexe */ - regmatch_t pmatch[3]; /* Correspondances de chaînes */ - size_t cmplen; /* Taille de comparaison */ - char *cast; /* Macro de transtypage */ - - dprintf(fd, "\tGArchInstruction *%s_decode_%s%s_%s%u(uint%u_t _raw)\n", - coder->arch, keyword, coder->details, spec->prefix, spec->index, wide); - - dprintf(fd, "\t{\n"); - - dprintf(fd, "\t\tGArchInstruction *instr;\n"); - - /* Déclaration des champs à retrouver */ - - for (i = 0; i < spec->bf_count; i++) - dprintf(fd, "\t\tuint%u_t raw_%s;\n", wide, spec->bitfields[i].name); - - for (i = 0; i < spec->items_count; i++) - if (!spec->items[i].internal) - { - dprintf(fd, "\t\tGArchOperand *op;\n"); - break; - } - - dprintf(fd, "\n"); - - /* Vérification que le décodage est possible */ - - dprintf(fd, "\t\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n", spec->mask, spec->bits); - - dprintf(fd, "\n"); - - /* Définition des champs bruts */ - - for (i = 0; i < spec->bf_count; i++) - { - bf = &spec->bitfields[i]; - dprintf(fd, "\t\traw_%s = (_raw >> %u) & 0x%llx;\n", bf->name, bf->start, (1ull << bf->length) - 1); - } - - dprintf(fd, "\n"); - - /* Inclusion des éventuelles règles */ - - if (!write_coder_spec_rules(coder, fd, spec, &exit)) - return false; - - /* Création de l'instruction en elle-même */ - - dprintf(fd, "\t\tinstr = g_%s_instruction_new(\"%s\");\n", coder->arch, coder->ins); - - dprintf(fd, "\n"); - - /* Création des opérandes */ - - bool build_arg_if_needed(const conv_func *conv) - { - - /* TODO : concaténation... */ - - return false; - - } - - ret = regcomp(&preg, "(g_([a-z0-9]*)_instruction)", REG_EXTENDED); - if (ret != 0) - { - fprintf(stderr, "Internal error: bad regular expression.\n"); - return false; - } - - - for (i = 0; i < spec->items_count; i++) - { - item = &spec->items[i]; - - conv = find_conversion_in_coder_spec(spec, item->name); - if (conv == NULL) - { - fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name); - return false; - } - - callable = find_macro_in_coder(coder, conv->func); - if (callable == NULL) - { - fprintf(stderr, "Error: expected function to store '%s'.\n", item->name); - return false; - } - - rebuild = build_arg_if_needed(conv); - - if (item->internal) - { - ret = regexec(&preg, callable, sizeof(pmatch) / sizeof(regmatch_t), pmatch, 0); - if (ret == REG_NOMATCH) - { - fprintf(stderr, "Internal error: bad function for dealing wih instruction: '%s'.\n", callable); - return false; - } - - /** - * La variable de résultat est de type 'GArchInstruction', - * donc toute fonction différente de g_arch_instruction_*() attend un transtypage... - */ - - cmplen = MAX(strlen(coder->arch), pmatch[2].rm_eo - pmatch[2].rm_so); - - if (strncmp("arch", &callable[pmatch[2].rm_so], cmplen) == 0) - dprintf(fd, "\t\tif (!%s(instr, %s%s))\n", - callable, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); - - else - { - cast = strndup(&callable[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); - - cast = make_string_upper(cast); - - dprintf(fd, "\t\tif (!%s(%s(instr), %s%s))\n", - callable, cast, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); - - free(cast); - - } - - dprintf(fd, "\t\t\tgoto bad_exit;\n"); - - } - - else - { - if (strchr(callable, '(') == NULL) - dprintf(fd, "\t\top = %s(%s%s);\n", - callable, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); - else - dprintf(fd, "\t\top = %s%s%s);\n", - callable, rebuild ? "" : "raw_", rebuild ? item->name : conv->arg); - dprintf(fd, "\t\tif (op == NULL) goto bad_exit;\n"); - - dprintf(fd, "\n"); - - if (item->flags & SIF_DECIMAL) - dprintf(fd, "\t\tg_imm_operand_set_display(G_IMM_OPERAND(op), IOD_DEC);\n"); - - dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n"); - - } - - dprintf(fd, "\n"); - - } - - regfree(&preg); - - /* Conclusion de la procédure */ - - if (exit) - { - dprintf(fd, "\t quick_exit:\n"); - dprintf(fd, "\n"); - } - - dprintf(fd, "\t\treturn instr;\n"); - - dprintf(fd, "\n"); - - dprintf(fd, "\t bad_exit:\n"); - - dprintf(fd, "\n"); - - dprintf(fd, "\t\tg_object_unref(G_OBJECT(instr));\n"); - dprintf(fd, "\t\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", - coder->arch, keyword, coder->details, spec->prefix, spec->index); - - dprintf(fd, "\n"); - - return true; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* MANIPULATIONS DE CHAINES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : str = chaîne de caractères à manipuler. [OUT] * -* * -* Description : Bascule toute une chaîne de caractères en (min|maj)uscules. * -* * -* Retour : Pointeur sur la chaîne fournie. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *_make_string_xxx(char *str, int (* fn) (int)) -{ - size_t max; /* Empleur du parcours */ - size_t i; /* Boucle de parcours */ - - max = strlen(str); - - for (i = 0; i < max; i++) - str[i] = fn(str[i]); - - return str; - -} - - -/****************************************************************************** -* * -* Paramètres : raw = données brutes en provenance de l'analyseur. * -* details = indique la nature de la chaîne à traiter. * -* * -* Description : Traduit une chaîne en élément de fonction C. * -* * -* Retour : Chaîne à libérer de la mémoire après usage. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *make_callable(const char *raw, bool details) -{ - char *result; /* Nom formaté à retourner */ - size_t max; /* Empleur du parcours */ - size_t i; /* Boucle de parcours */ - - result = strdup(raw); - - max = strlen(result); - - /* Première passe : on vire les virgules */ - - for (i = 0; i < max; i++) - if (result[i] == ',') - { - memmove(result + i, result + i + 1, max - i - 1); - max--; - } - - result[max] = '\0'; - - /* Deuxième passe : on bascule en minuscules */ - - result = make_string_lower(result); - - /* Troisième passe : on remplace les mauvais caractères */ - - for (i = 0; i < max; i++) - switch (result[i]) - { - case 'a' ... 'z': - case '0' ... '9': - break; - case '-': - result[i] = '_'; - break; - default: - result[i] = (i + 1 == max ? '\0' : '_'); - break; - } - - /** - * Dernière passe : on s'assure que le premier caractère n'est pas une lettre. - * On ajoute ici le préfixe '_' utilisé lors de la génération de prototypes ; - * en cas d'absence de détails, on ne se retrouve ainsi pas avec un '_' isolé. - */ - - if (details && result[0] != '_') - { - max = strlen(result) + 1; - result = (char *)realloc(result, max); - memmove(result + 1, result, max - 1); - result[0] = '_'; - } - - return result; - -} diff --git a/tools/coder.h b/tools/coder.h index c96f787..e72764c 100644 --- a/tools/coder.h +++ b/tools/coder.h @@ -28,6 +28,10 @@ #include <stdbool.h> +#include "pproc.h" +#include "spec.h" + + /* Suivi des constructions */ typedef struct _rented_coder rented_coder; @@ -55,11 +59,8 @@ void set_coder_arch(rented_coder *, const char *); /* Définit la base des protections des fichiers d'en-tête. */ void set_coder_header_base(rented_coder *, const char *); -/* Enregistre une correspondance en matière d'encodage. */ -void register_encoding_in_coder(rented_coder *, const char *, const char *); - -/* Constitue la matière d'un système de macros. */ -void define_macro_for_coder(rented_coder *, const char *, 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 *, const char *); @@ -69,6 +70,8 @@ void save_notes_for_coder(rented_coder *, char *, char *, const char *); /* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ +/* Fournit un lien vers les spécifications courantes. */ +encoding_spec *get_current_encoding_spec(const rented_coder *); /* Enregistre une définition supplémentaire. */ void push_encoding_spec(rented_coder *, char *, unsigned int); @@ -85,7 +88,7 @@ void register_named_field_in_coder(rented_coder *, char *, unsigned int); void register_bit_in_coder(rented_coder *, int); /* Indique le nombre de bits traités. */ -unsigned int count_coder_bits(const rented_coder *); +//unsigned int count_coder_bits(const rented_coder *); @@ -101,49 +104,13 @@ void register_syntax_item_in_coder(rented_coder *, char *, bool); /* Enregistre la function de conversion du brut à l'utile. */ -void register_conversion_in_coder(rented_coder *, char *, char *, char *); +void register_conversion_in_coder(rented_coder *, conv_func *); /* --------------------------- CONDITIONS ET CONSEQUENCES --------------------------- */ -/* Types de comparaison */ -typedef enum _CondCompType -{ - CCT_EQUAL, /* Egalité '==' */ - CCT_DIFF /* Différence '!=' */ - -} CondCompType; - -/* Types de combinaison d'expressions */ -typedef enum _CondOpType -{ - COT_AND, /* Combinaison ET ('&&') */ - COT_OR /* Combinaison OU ('||') */ - -} CondOpType; - -/* Conséquence en cas de condition remplie */ -typedef enum _CondActionType -{ - CAT_SEE /* Renvoi vers une instruction */ - -} CondActionType; - - -/* Expression d'une condition */ -typedef struct _cond_expr cond_expr; - - -/* Crée une expression conditionnelle simple. */ -cond_expr *build_simple_cond_expression(char *, CondCompType, char *); - -/* Crée une expression conditionnelle composée. */ -cond_expr *build_composed_cond_expression(cond_expr *, CondOpType, cond_expr *); - -/* Ajoute une règle complète à la définition d'un codage. */ -void add_conditional_rule_to_coder(rented_coder *, cond_expr *, CondActionType, const char *); diff --git a/tools/conv.c b/tools/conv.c new file mode 100644 index 0000000..323f63d --- /dev/null +++ b/tools/conv.c @@ -0,0 +1,1640 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * conv.c - substitutions de valeurs depuis un contenu binaire + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "conv.h" + + +#include <assert.h> +#include <ctype.h> +#include <malloc.h> +#include <regex.h> +#include <stdbool.h> +#include <string.h> +#include <sys/param.h> + + +#include "helpers.h" + + + + + +/* Types d'expressions représentés */ +typedef enum _ConvExprType +{ + CET_NAME, /* Désignation de variable */ + CET_NUMBER, /* Valeur codée en dur */ + CET_COMPOSED, /* Agrégat de champs divers */ + CET_UNARY, /* Opération unaire */ + CET_BINARY, /* Opération binaire */ + + CET_COUNT + +} ConvExprType; + + +/* Représentation d'une expression de conversion */ +struct _conv_expr_t +{ + ConvExprType type; + + bool declared; /* Expression déjà déclarée ? */ + bool defined; /* Expression déjà définie ? */ + + union + { + /* CET_NAME */ + char *name; /* Désignation de variable */ + + /* CET_NUMBER */ + unsigned long number; /* Valeur durablement définie */ + + /* CET_COMPOSED */ + struct + { + char **comp_items; /* Elements à agréger */ + size_t comp_count; /* Quantité de ces éléments */ + }; + + /* CET_UNARY */ + struct + { + conv_expr_t *un_expr; /* Expression à traiter */ + ConvUnaryOperation un_op; /* Type d'opération à mener */ + + }; + + /* CET_BINARY */ + struct + { + conv_expr_t *bin_expr1; /* Expression à traiter */ + conv_expr_t *bin_expr2; /* Expression à traiter */ + ConvBinaryOperation bin_op; /* Type d'opération à mener */ + + }; + + }; + +}; + + +/* Visite une expression en traitant en premier ses composantes. */ +typedef bool (* visit_expr_fc) (conv_expr_t *, int, const coding_bits *, const conv_list *, void *); + + +/* Détermine la taille en bits d'une expression donnée. */ +static bool compute_conv_expr_size(const conv_expr_t *, const coding_bits *, const conv_list *, unsigned int *); + +/* Visite une expression en traitant en premier ses composantes. */ +static bool visit_conv_expr(conv_expr_t *, visit_expr_fc, int, const coding_bits *, const conv_list *, void *); + +/* 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 **); + +/* S'assure du marquage des expressions pre-requises. */ +static bool ensure_conv_expr_content_fully_marked(conv_expr_t *, const coding_bits *, const conv_list *); + +/* S'assure de la déclaration des expressions pre-requises. */ +static bool ensure_conv_expr_content_fully_declared(conv_expr_t *, int, const coding_bits *, const conv_list *, unsigned int); + +/* S'assure de la définition des expressions pre-requises. */ +static bool ensure_conv_expr_content_fully_defined(conv_expr_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *); + +/* Définit une expression utilisée dans une conversion. */ +static bool define_conv_expr(conv_expr_t *, int, const coding_bits *, const conv_list *); + + + +/* ------------------------ LISTES D'ARGUMENTS DE CONVERSION ------------------------ */ + + +/* Liste d'expressions utilisées en arguments de conversion */ +struct _conv_arg_list_t +{ + conv_expr_t **items; /* Liste d'expressions */ + size_t count; /* Taille de cette liste */ + +}; + + +/* S'assure du marquage des expressions pre-requises. */ +static bool ensure_arg_list_content_fully_marked(conv_arg_list_t *, const coding_bits *, const conv_list *); + +/* S'assure de la déclaration des expressions pre-requises. */ +static bool ensure_arg_list_content_fully_declared(conv_arg_list_t *, int, const coding_bits *, const conv_list *, unsigned int); + +/* S'assure de la définition des expressions pre-requises. */ +static bool ensure_arg_list_content_fully_defined(conv_arg_list_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *); + +/* Définit les variables associées à un appel de fonction. */ +static bool define_arg_list(conv_arg_list_t *, int, const coding_bits *, const conv_list *); + + + +/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ + + +/* Fonction de conversion */ +struct _conv_func +{ + 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 */ + + union + { + conv_expr_t *expr; /* Valeur expressive directe */ + + struct + { + char *name; /* Fonction de conversion */ + conv_arg_list_t *args; /* Liste des arguments */ + + }; + + }; + +}; + + +/* Détermine la taille en bits du résultat d'une fonction. */ +static bool compute_conv_func_size(const conv_func *, const coding_bits *, const conv_list *, unsigned int *); + + + + + + +#define delete_conv_expr(e) + + + + + + +/* ---------------------------- ENSEMBLES DE CONVERSIONS ---------------------------- */ + + +/* Liste des fonctions de conversions présentes */ +struct _conv_list +{ + conv_func **functions; /* Fonctions de conversion */ + size_t func_count; /* Nombre de ces fonctions */ + +}; + + + + + + + + + + + + +/****************************************************************************** +* * +* Paramètres : name = désignation d'une variable quelconque. * +* * +* Description : Référence une variable en tant qu'expression de conversion. * +* * +* Retour : Nouvelle expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_expr_t *build_conv_expr_from_name(char *name) +{ + conv_expr_t *result; /* Structure à retourner */ + + result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); + + result->type = CET_NAME; + + result->name = make_string_lower(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : number = valeur à conserver dans sa forme brute. * +* * +* Description : Conserve une valeur en tant qu'expression de conversion. * +* * +* Retour : Nouvelle expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_expr_t *build_conv_expr_from_number(unsigned long number) +{ + conv_expr_t *result; /* Structure à retourner */ + + result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); + + result->type = CET_NUMBER; + + result->number = number; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item1 = premier élément à agréger. * +* item2 = second élément à agréger. * +* * +* Description : Construit une base d'expression de conversion composée. * +* * +* Retour : Nouvelle expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_expr_t *build_composed_conv_expr(char *item1, char *item2) +{ + conv_expr_t *result; /* Structure à retourner */ + + result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); + + result->type = CET_COMPOSED; + + result->comp_items = (char **)calloc(2, sizeof(char *)); + result->comp_count = 2; + + result->comp_items[0] = make_string_lower(item1); + result->comp_items[1] = make_string_lower(item2); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression déjà en place à compléter. * +* item = nouvel élément à agréger. * +* * +* Description : Etend une base d'expression de conversion composée. * +* * +* Retour : Expression en place et mise à jour. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_expr_t *extend_composed_conv_expr(conv_expr_t *expr, char *item) +{ + assert(expr->type == CET_COMPOSED); + + expr->comp_items = (char **)realloc(expr->comp_items, ++expr->comp_count * sizeof(char *)); + + expr->comp_items[expr->comp_count - 1] = make_string_lower(item); + + return expr; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression à encapsuler. * +* op = opération unaire à associer à l'opération. * +* * +* Description : Traduit une opération unaire sur expression de conversion. * +* * +* Retour : Nouvelle expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_expr_t *build_unary_conv_expr(conv_expr_t *expr, ConvUnaryOperation op) +{ + conv_expr_t *result; /* Structure à retourner */ + + result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); + + result->type = CET_UNARY; + + result->un_expr = expr; + result->un_op = op; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr1 = première expression à encapsuler. * +* expr2 = seconde expression à encapsuler. * +* op = opération binaire à associer à l'opération. * +* * +* Description : Traduit une opération binaire sur expression de conversion. * +* * +* Retour : Nouvelle expression mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_expr_t *build_binary_conv_expr(conv_expr_t *expr1, conv_expr_t *expr2, ConvBinaryOperation op) +{ + conv_expr_t *result; /* Structure à retourner */ + + result = (conv_expr_t *)calloc(1, sizeof(conv_expr_t)); + + result->type = CET_BINARY; + + result->bin_expr1 = expr1; + result->bin_expr2 = expr2; + result->bin_op = op; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première expression à 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] * +* * +* Description : Détermine la taille en bits d'une expression donnée. * +* * +* Retour : true si la taille a pu être déterminée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool compute_conv_expr_size(const conv_expr_t *expr, const coding_bits *bits, const conv_list *list, unsigned int *size) +{ + bool result; /* Bilan à retourner */ + raw_bitfield *field; /* Eventuel champ brut associé */ + conv_func *func; /* Eventuelle fonction liée */ + size_t i; /* Boucle de parcours */ + unsigned int tmp; /* Stockage temporaire */ + + switch (expr->type) + { + case CET_NAME: + + result = find_var_by_name(bits, list, expr->name, &field, &func); + + if (result) + { + if (field != NULL) + *size = get_raw_bitfield_length(field); + else + result = compute_conv_func_size(func, bits, list, size); + } + + break; + + case CET_COMPOSED: + + result = true; + *size = 0; + + for (i = 0; i < expr->comp_count && result; i++) + { + if (isdigit(expr->comp_items[i][0])) + *size += strlen(expr->comp_items[i]); + + else + { + if (!find_var_by_name(bits, list, expr->comp_items[i], &field, &func)) + result = false; + + else + { + if (field != NULL) + *size += get_raw_bitfield_length(field); + else + { + result = compute_conv_func_size(func, bits, list, &tmp); + *size += tmp; + } + } + + } + + } + + break; + + case CET_UNARY: + result = compute_conv_expr_size(expr->un_expr, bits, list, size); + break; + + case CET_BINARY: + + result = compute_conv_expr_size(expr->bin_expr1, bits, list, &tmp); + + if (result) + result = compute_conv_expr_size(expr->bin_expr1, bits, list, size); + + if (tmp > *size) *size = tmp; + + break; + + default: + result = false; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : Visite une expression en traitant en premier ses composantes.* +* * +* Retour : Bilan des traitements effectués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool visit_conv_expr(conv_expr_t *expr, visit_expr_fc visit, int fd, const coding_bits *bits, const conv_list *list, void *data) +{ + bool result; /* Bilan à retourner */ + + switch (expr->type) + { + case CET_UNARY: + result = visit_conv_expr(expr->un_expr, visit, fd, bits, list, data); + break; + + case CET_BINARY: + result = visit_conv_expr(expr->bin_expr1, visit, fd, bits, list, data); + result = visit_conv_expr(expr->bin_expr2, visit, fd, bits, list, data); + break; + + default: + result = true; + break; + + } + + result &= visit(expr, fd, bits, list, data); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* name = déssignation de la variable recherchée. * +* field = éventuel élement brut de décodage. * +* func = éventuelle fonction de conversion pour intermédiaire.* +* * +* Description : Retrouve si elle existe une variable manipulée. * +* * +* Retour : Bilan des recherches : trouvaille ou non ? * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool find_var_by_name(const coding_bits *bits, const conv_list *list, const char *name, raw_bitfield **field, conv_func **func) +{ + bool result; /* Bilan à retourner */ + raw_bitfield *cached_field; /* Champ, version cachée */ + conv_func *cached_func; /* Fonction, version cachée */ + + cached_field = find_named_field_in_bits(bits, name); + result = (cached_field != NULL); + + if (!result) + { + cached_func = find_named_conv_in_list(list, name); + result = (cached_func != NULL); + } + else + cached_func = NULL; + + if (field != NULL) *field = cached_field; + if (func != NULL) *func = cached_func; + + if (!result) + fprintf(stderr, "Variable '%s' not found!\n", name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = première expression à encapsuler. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* * +* Description : S'assure du marquage des expressions pre-requises. * +* * +* Retour : Bilan des traitements effectués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool ensure_conv_expr_content_fully_marked(conv_expr_t *expr, const coding_bits *bits, const conv_list *list) +{ + bool mark_sub_expr(conv_expr_t *sub, int dummy, const coding_bits *bts, const conv_list *lst, void *unused) + { + 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 found; /* Bilan d'opération à renvoyer*/ + raw_bitfield *field; /* Eventuel champ brut associé */ + + found = find_var_by_name(bts, lst, name, &field, NULL); + + if (found && field != NULL) + mark_raw_bitfield_as_used(field); + + return found; + + } + + /* Il est uniquement nécessaire de s'attacher aux références */ + switch (sub->type) + { + case CET_NAME: + result = mark_by_name(bits, lst, sub->name); + break; + + case CET_COMPOSED: + 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]); + break; + + default: + result = true; + break; + + } + + return result; + + } + + return visit_conv_expr(expr, (visit_expr_fc)mark_sub_expr, -1, bits, list, NULL); + +} + + +/****************************************************************************** +* * +* 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. * +* wide = taille des mots décodés. * +* * +* Description : S'assure de la déclaration des expressions pre-requises. * +* * +* Retour : Bilan des traitements effectués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool ensure_conv_expr_content_fully_declared(conv_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) +{ + bool declare_sub_expr(conv_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, unsigned int *wide) + { + 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... */ + if (sub->declared) return true; + + bool declare_by_name(int _f, const coding_bits *_bts, const conv_list *_lst, unsigned int _wide, 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); + + if (found && func != NULL) + { + dprintf(_f, "\t\tuint%u_t val_%s;\n", _wide, name); + found = declare_conv_func(func, _f, _bts, _lst, _wide); + } + + return found; + + } + + /* Il est uniquement nécessaire de s'attacher aux références */ + switch (sub->type) + { + case CET_NAME: + result = declare_by_name(f, bits, lst, *wide, sub->name); + break; + + case CET_COMPOSED: + result = true; + for (i = 0; i < sub->comp_count && result; i++) + if (!isdigit(sub->comp_items[i][0])) + printf("... trying to declare... '%s'\n", sub->comp_items[i]); + for (i = 0; i < sub->comp_count && result; i++) + if (!isdigit(sub->comp_items[i][0])) + result = declare_by_name(f, bits, lst, *wide, sub->comp_items[i]); + break; + + default: + result = true; + break; + + } + + sub->declared = result; + + return result; + + } + + return visit_conv_expr(expr, (visit_expr_fc)declare_sub_expr, fd, bits, list, &wide); + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : S'assure de la définition des expressions pre-requises. * +* * +* Retour : Bilan des traitements effectués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool ensure_conv_expr_content_fully_defined(conv_expr_t *expr, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp) +{ + typedef struct _def_info + { + const char *arch; + const pre_processor *pp; + + } def_info; + + def_info info; /* Transmissions au visiteur */ + + bool define_sub_expr(conv_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, def_info *info) + { + 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... */ + 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 found; /* Bilan d'opération à renvoyer*/ + conv_func *func; /* Eventuelle fonction liée */ + + found = find_var_by_name(bts, lst, name, NULL, &func); + + if (found && func != NULL) + found = define_conv_func(func, false, false, _f, _info->arch, _bts, _lst, _info->pp); + + return found; + + } + + /* Il est uniquement nécessaire de s'attacher aux références */ + switch (sub->type) + { + case CET_NAME: + result = define_by_name(f, bits, lst, info, sub->name); + break; + + case CET_COMPOSED: + 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]); + break; + + default: + result = true; + break; + + } + + sub->defined = result; + + return result; + + } + + info.arch = arch; + info.pp = pp; + + return visit_conv_expr(expr, (visit_expr_fc)define_sub_expr, fd, bits, list, &info); + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : Définit une expression utilisée dans une conversion. * +* * +* Retour : Bilan des traitements effectués. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool define_conv_expr(conv_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list) +{ + bool result; /* Bilan à retourner */ + raw_bitfield *field; /* Eventuel champ brut associé */ + conv_func *func; /* Eventuelle fonction liée */ + unsigned int max_size; /* Quantité de bits totale */ + size_t i; /* Boucle de parcours */ + const char *cname; /* Raccourci de confort */ + unsigned int used_size; /* Quantité de bits utilisée */ + + result = true; + + switch (expr->type) + { + case CET_NAME: + + if (!find_var_by_name(bits, list, expr->name, &field, &func)) + result = false; + + else + { + if (field != NULL) + dprintf(fd, "raw_%s", expr->name); + else + dprintf(fd, "val_%s", expr->name); + } + + break; + + case CET_NUMBER: + dprintf(fd, "%lu", expr->number); + break; + + case CET_COMPOSED: + + result = compute_conv_expr_size(expr, bits, list, &max_size); + + printf("MAX SIZE :: %u\n", max_size); + + for (i = 0; i < expr->comp_count && result; i++) + { + cname = expr->comp_items[i]; + + if (i > 0) + dprintf(fd, " | "); + + /* Constante binaire ? */ + if (isdigit(cname[0])) + { + max_size -= strlen(cname); + + if (max_size == 0) + dprintf(fd, "b%s", cname); + else + dprintf(fd, "b%s << %u", cname, max_size); + + } + + /* Ou variable définie ? */ + else + { + result = find_var_by_name(bits, list, cname, &field, &func); + + if (result) + { + if (field != NULL) + used_size = get_raw_bitfield_length(field); + else + /*result = */compute_conv_func_size(func, bits, list, &used_size); + + max_size -= used_size; + + if (field != NULL) + { + if (max_size == 0) + dprintf(fd, "raw_%s", cname); + else + dprintf(fd, "raw_%s << %u", cname, max_size); + } + else + { + if (max_size == 0) + dprintf(fd, "val_%s", cname); + else + dprintf(fd, "val_%s << %u", cname, max_size); + } + + } + + } + + } + + break; + + case CET_UNARY: + + switch (expr->un_op) + { + case CUO_NOT: + dprintf(fd, "!"); + break; + default: + result = false; + break; + } + + result &= define_conv_expr(expr->un_expr, fd, bits, list); + + break; + + case CET_BINARY: + + dprintf(fd, "("); + + result = define_conv_expr(expr->bin_expr1, fd, bits, list); + + switch (expr->bin_op) + { + case CBO_EOR: + dprintf(fd, " ^ "); + break; + default: + result = false; + break; + } + + result &= define_conv_expr(expr->bin_expr2, fd, bits, list); + + dprintf(fd, ")"); + + break; + + default: + result = false; + break; + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* LISTES D'ARGUMENTS DE CONVERSION */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : expr = expression initial pour constituer une liste. * +* * +* Description : Crée une liste d'arguments de conversion. * +* * +* Retour : Nouvelle structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_arg_list_t *build_conv_arg_list(conv_expr_t *expr) +{ + conv_arg_list_t *result; /* Structure à retourner */ + + result = (conv_arg_list_t *)calloc(1, sizeof(conv_arg_list_t)); + + result->items = (conv_expr_t **)calloc(1, sizeof(conv_expr_t *)); + result->count = 1; + + result->items[0] = expr; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste d'expressions à supprimer de la mémoire. * +* * +* Description : Libère la mémoire occupée par une liste d'expressions. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_conv_arg_list(conv_arg_list_t *list) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < list->count; i++) + delete_conv_expr(list->items[i]); + + if (list->items != NULL) + free(list->items); + + free(list); + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste d'expressions à supprimer de la mémoire. [OUT] * +* expr = expression à ajouter à la liste courante. * +* * +* Description : Ajoute un élément à une liste d'arguments de conversion. * +* * +* Retour : Structure en place mise à jour. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_arg_list_t *extend_conv_arg_list(conv_arg_list_t *list, conv_expr_t *expr) +{ + list->items = (conv_expr_t **)realloc(list->items, ++list->count * sizeof(conv_expr_t *)); + + list->items[list->count - 1] = expr; + + return list; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : S'assure du marquage des expressions pre-requises. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool ensure_arg_list_content_fully_marked(conv_arg_list_t *args, const coding_bits *bits, const conv_list *list) +{ + bool result; /* Bilan à remonter */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < args->count && result; i++) + result = ensure_conv_expr_content_fully_marked(args->items[i], bits, list); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : args = liste d'expressions à supprimer de la mémoire. * +* 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. * +* * +* Description : S'assure de la déclaration des expressions pre-requises. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool ensure_arg_list_content_fully_declared(conv_arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) +{ + bool result; /* Bilan à remonter */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < args->count && result; i++) + result = ensure_conv_expr_content_fully_declared(args->items[i], fd, bits, list, wide); + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : S'assure de la définition des expressions pre-requises. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool ensure_arg_list_content_fully_defined(conv_arg_list_t *args, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp) +{ + bool result; /* Bilan à remonter */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < args->count && result; i++) + result = ensure_conv_expr_content_fully_defined(args->items[i], fd, arch, bits, list, pp); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : args = liste d'expressions à supprimer de la mémoire. * +* fd = descripteur d'un flux ouvert en écriture. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* * +* Description : Définit les variables associées à un appel de fonction. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool define_arg_list(conv_arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list) +{ + bool result; /* Bilan à remonter */ + size_t i; /* Boucle de parcours */ + + result = true; + + for (i = 0; i < args->count && result; i++) + { + if (i > 0) dprintf(fd, ", "); + result = define_conv_expr(args->items[i], fd, bits, list); + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONVERSION DES ARGUMENTS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : dest = désignation de la variable de destination. * +* expr = expression dont la valeur est à assigner. * +* * +* Description : Définit une conversion à partir d'une simple expression. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_func *make_conv_from_expr(char *dest, conv_expr_t *expr) +{ + conv_func *result; /* Conversion à retourner */ + + result = (conv_func *)calloc(1, sizeof(conv_func)); + + result->dest = make_string_lower(dest); + + result->is_expr = true; + result->expr = expr; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dest = désignation de la variable de destination. * +* func = nom de la fonction assurant le calcul de valeur. * +* args = argument(s) à fournir à cette fonction. * +* * +* Description : Définit une conversion à partir d'une function à appeler. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_func *make_conv_from_func(char *dest, char *func, conv_arg_list_t *args) +{ + conv_func *result; /* Conversion à retourner */ + + result = (conv_func *)calloc(1, sizeof(conv_func)); + + result->dest = make_string_lower(dest); + + result->is_expr = false; + result->name = func; + result->args = args; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : func = éléments de conversion à supprimer de la mémoire. * +* * +* Description : Libère de la mémoire une conversion enregistrée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_conv_func(conv_func *func) +{ + if (func->is_expr) + delete_conv_expr(func->expr); + + else + { + free(func->name); + delete_conv_arg_list(func->args); + } + + free(func); + +} + + +/****************************************************************************** +* * +* Paramètres : func = fonction de conversion à consulter. * +* * +* Description : Indique la variable de destination d'une conversion. * +* * +* Retour : Désignation humaine de la variable de destination. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *get_conv_dest_name(const conv_func *func) +{ + return func->dest; + +} + + +/****************************************************************************** +* * +* 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] * +* * +* Description : Détermine la taille en bits du résultat d'une fonction. * +* * +* Retour : true si la taille a pu être déterminée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool compute_conv_func_size(const conv_func *func, const coding_bits *bits, const conv_list *list, unsigned int *size) +{ + bool result; /* Bilan à retourner */ + + result = func->is_expr; + + if (result) + result = compute_conv_expr_size(func->expr, bits, list, size); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : func = fonction de conversion à manipuler. * +* bits = gestionnaire des bits d'encodage. * +* list = liste de l'ensemble des fonctions de conversion. * +* * +* Description : Marque les champs utilisés par une fonction de conversion. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool mark_conv_func(conv_func *func, const coding_bits *bits, const conv_list *list) +{ + bool result; /* Bilan à remonter */ + + if (func->is_expr) + result = ensure_conv_expr_content_fully_marked(func->expr, bits, list); + else + result = ensure_arg_list_content_fully_marked(func->args, bits, list); + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* wide = taille des mots décodés. * +* * +* Description : Déclare les variables associées à une fonction de conversion.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool declare_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) +{ + bool result; /* Bilan à remonter */ + + /* 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_conv_expr_content_fully_declared(func->expr, fd, bits, list, wide); + else + result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, wide); + + func->declared = result; + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : Définit les variables associées à une fonction de conversion.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +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 result; /* Bilan à remonter */ + const char *callable; /* Fonction à appeler */ + regex_t preg; /* Expression régulière */ + int ret; /* Bilan d'une manipulation */ + regmatch_t pmatch[3]; /* Correspondances de chaînes */ + size_t cmplen; /* Taille de comparaison */ + char *cast; /* Macro de transtypage */ + + /* Si la fonction a déjà été définie lors d'un précédent besoin... */ + if (func->defined) return true; + + if (func->is_expr) + result = ensure_conv_expr_content_fully_defined(func->expr, fd, arch, bits, list, pp); + else + result = ensure_arg_list_content_fully_defined(func->args, fd, arch, bits, list, pp); + + /* Nom de la fonction effectivement appelée */ + + if (!func->is_expr) + { + callable = find_macro(pp, func->name); + + if (callable == NULL) + callable = func->name; + + } + else callable = NULL; + + if (last && callable == NULL) + { + fprintf(stderr, "Error: expected function to store '%s'.\n", func->dest); + return false; + } + + /* Dernier niveau : la variable de destination est imposée ! */ + if (last) + { + /* Si l'on doit manipuler une propriété d'instructon... */ + if (internal) + { + ret = regcomp(&preg, "(g_([a-z0-9]*)_instruction)", REG_EXTENDED); + if (ret != 0) + { + fprintf(stderr, "Internal error: bad regular expression.\n"); + return false; + } + + ret = regexec(&preg, callable, sizeof(pmatch) / sizeof(regmatch_t), pmatch, 0); + if (ret == REG_NOMATCH) + { + fprintf(stderr, "Internal error: bad function for dealing wih instruction: '%s'.\n", callable); + result = false; + goto dcf_skip_internal; + } + + /** + * La variable de résultat est de type 'GArchInstruction', + * donc toute fonction différente de g_arch_instruction_*() attend un transtypage... + */ + + cmplen = MAX(strlen(arch), pmatch[2].rm_eo - pmatch[2].rm_so); + + if (strncmp("arch", &callable[pmatch[2].rm_so], cmplen) == 0) + dprintf(fd, "\t\tif (!%s(instr, ", callable); + + else + { + cast = strndup(&callable[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); + + cast = make_string_upper(cast); + + dprintf(fd, "\t\tif (!%s(%s(instr), ", callable, cast); + + free(cast); + + } + + result &= define_arg_list(func->args, fd, bits, list); + + dprintf(fd, "))\n"); + + dcf_skip_internal: + + regfree(&preg); + + } + + /* 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); + + result &= define_arg_list(func->args, fd, bits, list); + + 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_conv_expr(func->expr, fd, bits, list); + + else + { + dprintf(fd, "%s(", callable); + + result = define_arg_list(func->args, fd, bits, list); + + dprintf(fd, ")"); + + } + + dprintf(fd, ";\n"); + + } + + func->defined = result; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* ENSEMBLES DE CONVERSIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouvelle liste vierge de fonctions de conversion. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_list *create_conv_list(void) +{ + conv_list *result; /* Définition vierge à renvoyer*/ + + result = (conv_list *)calloc(1, sizeof(conv_list)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de fonctions de conversion à supprimer. * +* * +* Description : Supprime de la mémoire une de fonctions de conversion. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_conv_list(conv_list *list) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < list->func_count; i++) + delete_conv_func(list->functions[i]); + + if (list->functions != NULL) + free(list->functions); + + free(list); + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste de fonctions de conversion à compléter. * +* func = nom de la fonction assurant le calcul de valeur. * +* * +* Description : Enregistre une function de conversion du brut à l'utile. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_conversion(conv_list *list, conv_func *func) +{ + list->functions = (conv_func **)realloc(list->functions, ++list->func_count * sizeof(conv_func *)); + + list->functions[list->func_count - 1] = func; + +} + + +/****************************************************************************** +* * +* Paramètres : list = liste de fonctions de conversion à consulter. * +* name = désignation humaine du champ à retrouver. * +* * +* Description : Recherche un résultat précis dans une liste de fonctions. * +* * +* Retour : Structure associée au résulat trouvé ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +conv_func *find_named_conv_in_list(const conv_list *list, const char *name) +{ + conv_func *result; /* Fonction à retourner */ + size_t i; /* Boucle de parcours */ + const char *dest; /* Nom de variable existante */ + + result = NULL; + + for (i = 0; i < list->func_count && result == NULL; i++) + { + dest = get_conv_dest_name(list->functions[i]); + + if (strcmp(dest, name) == 0) + result = list->functions[i]; + + } + + return result; + +} diff --git a/tools/conv.h b/tools/conv.h new file mode 100644 index 0000000..acf007b --- /dev/null +++ b/tools/conv.h @@ -0,0 +1,160 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * conv.h - prototypes pour les substitutions de valeurs depuis un contenu binaire + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_CONV_H +#define _TOOLS_CONV_H + + +#include "bits.h" +#include "pproc.h" + + + + +/* Liste des fonctions de conversions présentes */ +typedef struct _conv_list conv_list; + + + + + + + +/* Types d'opérations unaires */ +typedef enum _ConvUnaryOperation +{ + CUO_NOT, /* NOT (booléen) */ + + CUO_COUNT + +} ConvUnaryOperation; + + + +/* Types d'opérations binaires */ +typedef enum _ConvBinaryOperation +{ + CBO_EOR, /* Ou exclusif (booléen) */ + + CBO_COUNT + +} ConvBinaryOperation; + + +/* Représentation d'une expression de conversion */ +typedef struct _conv_expr_t conv_expr_t; + + + +/* Référence une variable en tant qu'expression de conversion. */ +conv_expr_t *build_conv_expr_from_name(char *); + +/* Conserve une valeur en tant qu'expression de conversion. */ +conv_expr_t *build_conv_expr_from_number(unsigned long ); + +/* Construit une base d'expression de conversion composée. */ +conv_expr_t *build_composed_conv_expr(char *, char *); + +/* Etend une base d'expression de conversion composée. */ +conv_expr_t *extend_composed_conv_expr(conv_expr_t *, char *); + +/* Traduit une opération unaire sur expression de conversion. */ +conv_expr_t *build_unary_conv_expr(conv_expr_t *, ConvUnaryOperation); + +/* Traduit une opération binaire sur expression de conversion. */ +conv_expr_t *build_binary_conv_expr(conv_expr_t *, conv_expr_t *, ConvBinaryOperation); + + + + + + + + +/* ------------------------ LISTES D'ARGUMENTS DE CONVERSION ------------------------ */ + + +/* Liste d'expressions utilisées en arguments de conversion */ +typedef struct _conv_arg_list_t conv_arg_list_t; + + +/* Crée une liste d'arguments de conversion. */ +conv_arg_list_t *build_conv_arg_list(conv_expr_t *); + +/* Libère la mémoire occupée par une liste d'expressions. */ +void delete_conv_arg_list(conv_arg_list_t *); + +/* Ajoute un élément à une liste d'arguments de conversion. */ +conv_arg_list_t *extend_conv_arg_list(conv_arg_list_t *, conv_expr_t *); + + + + +/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ + + +/* Fonction de conversion */ +typedef struct _conv_func conv_func; + + +/* Définit une conversion à partir d'une simple expression. */ +conv_func *make_conv_from_expr(char *, conv_expr_t *); + +/* Définit une conversion à partir d'une function à appeler. */ +conv_func *make_conv_from_func(char *, char *, conv_arg_list_t *); + +/* Libère de la mémoire une conversion enregistrée. */ +void delete_conv_func(conv_func *); + +/* Indique la variable de destination d'une conversion. */ +const char *get_conv_dest_name(const conv_func *); + +/* Marque les champs utilisés par une fonction de conversion. */ +bool mark_conv_func(conv_func *, 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 *, unsigned int); + +/* 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 *); + + + +/* ---------------------------- ENSEMBLES DE CONVERSIONS ---------------------------- */ + + +/* Crée un nouvelle liste vierge de fonctions de conversion. */ +conv_list *create_conv_list(void); + +/* Supprime de la mémoire une de fonctions de conversion. */ +void delete_conv_list(conv_list *); + +/* Enregistre une function de conversion du brut à l'utile. */ +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 *); + + + +#endif /* _TOOLS_CONV_H */ diff --git a/tools/d2c_gram.y b/tools/d2c_gram.y index 6fc8fb7..5deb053 100644 --- a/tools/d2c_gram.y +++ b/tools/d2c_gram.y @@ -9,6 +9,7 @@ #include "coder.h" +#include "d2c_tok.h" extern int yylex(); @@ -17,10 +18,10 @@ extern void free_flex_memory(void); /* Affiche un message d'erreur suite à l'analyse en échec. */ -static int d2c_error(rented_coder *coder, char *s); +static int d2c_error(rented_coder *, char *); /* Affiche des indications sur l'utilisation du programme. */ -static void show_usage(const char *argv0); +static void show_usage(const char *); %} @@ -31,12 +32,76 @@ static void show_usage(const char *argv0); /* Pour la définition des expressions conditionnelles... */ #include "coder.h" +#include "conv.h" + struct action_tmp { CondActionType action; const char *details; }; + + + +#define register_named_field_in_coder(c, n, l) \ + ({ \ + encoding_spec *__spec; \ + coding_bits *__bits; \ + __spec = get_current_encoding_spec(c); \ + __bits = get_bits_in_encoding_spec(__spec); \ + register_named_field_in_bits(__bits, n, l); \ + }) + +#define register_bit_in_coder(c, v) \ + ({ \ + encoding_spec *__spec; \ + coding_bits *__bits; \ + __spec = get_current_encoding_spec(c); \ + __bits = get_bits_in_encoding_spec(__spec); \ + register_bit_in_bits(__bits, v); \ + }) + +#define count_coder_bits(c) \ + ({ \ + encoding_spec *__spec; \ + coding_bits *__bits; \ + __spec = get_current_encoding_spec(c); \ + __bits = get_bits_in_encoding_spec(__spec); \ + count_coded_bits(__bits); \ + }) + +#define register_syntax_item_in_coder(c, n, i) \ + ({ \ + encoding_spec *__spec; \ + asm_syntax *__syntax; \ + __spec = get_current_encoding_spec(c); \ + __syntax = get_syntax_in_encoding_spec(__spec); \ + register_syntax_item(__syntax, n, i); \ + }) + +#define register_conversion_in_coder(c, f) \ + ({ \ + encoding_spec *__spec; \ + conv_list *__list; \ + __spec = get_current_encoding_spec(c); \ + __list = get_conversions_in_encoding_spec(__spec); \ + register_conversion(__list, f); \ + }) + +#define add_conditional_rule_to_coder(c, e, a, d) \ + ({ \ + encoding_spec *__spec; \ + decoding_rules *__rules; \ + __spec = get_current_encoding_spec(c); \ + __rules = get_rules_in_encoding_spec(__spec); \ + register_conditional_rule(__rules, e, a, d); \ + }) + + + + + + } %union { @@ -47,6 +112,13 @@ struct action_tmp int integer; + conv_func *subst; /* Fonction de conversion */ + conv_arg_list_t *conv_list; /* Liste d'arguments de conv. */ + + conv_expr_t *conv; /* Expression de conversion */ + ConvUnaryOperation un_op; /* Opération unaire */ + ConvBinaryOperation bin_op; /* Opération bianire */ + cond_expr *expr; /* Expression de déclenchement */ struct action_tmp tmpa; /* Transfert temporaire */ @@ -68,7 +140,7 @@ struct action_tmp %token SYNTAX OPERAND_INTERNAL OPERAND_VISIBLE -%token CONV EQ ARG +%token CONV EQ OP COMMA CP NOT EOR COLON %token RULES IF EXPR_START EQUAL BINVAL EXPR_END AND THEN SEE @@ -83,7 +155,13 @@ struct action_tmp %type <string> OPERAND_INTERNAL OPERAND_VISIBLE -%type <string> ARG + +%type <subst> substitution +%type <conv_list> conv_arg_list +%type <conv> conv_expr conv_arg_composed +%type <un_op> conv_expr_un_op +%type <bin_op> conv_expr_bin_op +%type <string> conv_arg_field %type <expr> rule_cond %type <string> BINVAL @@ -115,8 +193,20 @@ content : /* empty */ | rules content -bitfield : HALF bits { if (count_coder_bits(coder) != 16) YYABORT; } - | WORD bits { if (count_coder_bits(coder) != 32) YYABORT; } +bitfield : HALF bits { + if (count_coder_bits(coder) != 16) + { + fprintf(stderr, "Unexpected word size: %u vs 16\n", count_coder_bits(coder)); + YYABORT; + } + } + | WORD bits { + if (count_coder_bits(coder) != 32) + { + fprintf(stderr, "Unexpected word size: %u vs 32\n", count_coder_bits(coder)); + YYABORT; + } + } bits : /* empty */ | NAME SIZE bits { register_named_field_in_coder(coder, $1, $2); } @@ -133,7 +223,30 @@ operands : /* empty */ conversions : CONV substitutions substitutions : /* empty */ - | substitutions NAME EQ NAME ARG { register_conversion_in_coder(coder, $2, $4, $5); } + | substitutions substitution { register_conversion_in_coder(coder, $2); } + +substitution : NAME EQ conv_expr { $$ = make_conv_from_expr($1, $3); } + | NAME EQ NAME OP conv_arg_list CP { $$ = make_conv_from_func($1, $3, $5); } + +conv_arg_list : conv_expr { $$ = build_conv_arg_list($1); } + | conv_arg_list COMMA conv_expr { $$ = extend_conv_arg_list($1, $3); printf("extend\n"); } + +conv_expr : NAME { $$ = build_conv_expr_from_name($1); } + | NUMBER { $$ = build_conv_expr_from_number($1); } + | conv_arg_composed { $$ = $1; } + | OP conv_expr CP { $$ = $2; } + | conv_expr_un_op conv_expr { $$ = build_unary_conv_expr($2, $1); } + | OP conv_expr conv_expr_bin_op conv_expr CP { $$ = build_binary_conv_expr($2, $4, $3); } + +conv_expr_un_op : NOT { $$ = CUO_NOT; } + +conv_expr_bin_op : EOR { $$ = CBO_EOR; } + +conv_arg_composed : conv_arg_field COLON conv_arg_field { $$ = build_composed_conv_expr($1, $3); } + | conv_arg_composed COLON conv_arg_field { $$ = extend_composed_conv_expr($1, $3); } + +conv_arg_field : NAME { $$ = $1; printf(" composed::name '%s'\n", $1); } + | BINVAL { $$ = $1; printf(" composed::bin '%s'\n", $1); } rules : RULES rules_list @@ -169,7 +282,7 @@ action : SEE INS_DETAILS { $$.action = CAT_SEE; $$.details = $2; } static int d2c_error(rented_coder *coder, char *msg) { - printf("yyerror : %s\n", msg); + printf("yyerror line %d: %s\n", d2c_get_lineno(), msg); return 0; @@ -287,7 +400,7 @@ int main(int argc, char **argv) if (!has_error) { *sep = '\0'; - register_encoding_in_coder(coder, optarg, sep + 1); + register_encoding(get_coder_pre_proc(coder), optarg, sep + 1); } break; @@ -300,7 +413,7 @@ int main(int argc, char **argv) if (!has_error) { *sep = '\0'; - define_macro_for_coder(coder, optarg, sep + 1); + define_macro(get_coder_pre_proc(coder), optarg, sep + 1); } break; diff --git a/tools/d2c_tok.l b/tools/d2c_tok.l index ae4faa3..50a8d8f 100644 --- a/tools/d2c_tok.l +++ b/tools/d2c_tok.l @@ -19,6 +19,7 @@ void free_flex_memory(void) ; %option noyywrap %option nounput %option noinput +%option yylineno %x comments @@ -30,7 +31,7 @@ void free_flex_memory(void) ; %x syntax syntax_int syntax_ext -%x conv_begin conv_content conv_arg +%x conv_begin conv_content conv_arg conv_arg_binval %x rules_begin rules_content rules_cond rules_cond_binval rules_action rules_actin_see @@ -51,7 +52,7 @@ void free_flex_memory(void) ; "@title" { BEGIN(ins_name); return TITLE; } <ins_name>[ ][A-Za-z-]+ { d2c_lval.string = strdup(yytext + 1); BEGIN(try_details); return INS_NAME; } -<try_details>[ ] { BEGIN(ins_details); } +<try_details>[ ,/] { BEGIN(ins_details); } <try_details>[\n] { BEGIN(INITIAL); } <ins_details>[^\n]* { d2c_lval.cstring = yytext; return INS_DETAILS; } @@ -111,12 +112,33 @@ void free_flex_memory(void) ; <conv_content>"}" { BEGIN(encoding_content); } <conv_content>[ \t\n]+ { } -<conv_content>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } +<conv_content>[A-Za-z][A-Za-z0-9]* { + if (strcmp(yytext, "NOT") == 0) return NOT; + else + { + d2c_lval.string = strdup(yytext); + return NAME; + } + } <conv_content>"=" { return EQ; } - -<conv_content>"(" { BEGIN(conv_arg); } -<conv_arg>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return ARG; } -<conv_arg>")" { BEGIN(conv_content); } +<conv_content>"(" { BEGIN(conv_arg); return OP; } +<conv_arg>[A-Za-z][A-Za-z0-9]* { + if (strcmp(yytext, "NOT") == 0) return NOT; + else if (strcmp(yytext, "EOR") == 0) return EOR; + else + { + d2c_lval.string = strdup(yytext); + return NAME; + } + } +<conv_arg>[0-9][0-9]* { d2c_lval.integer = atoi(yytext); return NUMBER; } +<conv_arg>"'" { BEGIN(conv_arg_binval); } +<conv_arg_binval>[01][01]* { d2c_lval.string = strdup(yytext); return BINVAL; } +<conv_arg_binval>"'" { BEGIN(conv_arg); } +<conv_arg>"," { return COMMA; } +<conv_arg>":" { return COLON; } +<conv_arg>[ ]+ { } +<conv_arg>")" { BEGIN(conv_content); return CP; } diff --git a/tools/helpers.c b/tools/helpers.c new file mode 100644 index 0000000..1353ba2 --- /dev/null +++ b/tools/helpers.c @@ -0,0 +1,144 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers.c - fonctionnalités d'assitance à la compilation + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "helpers.h" + + +#include <malloc.h> +#include <string.h> + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATIONS DE CHAINES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : str = chaîne de caractères à manipuler. [OUT] * +* * +* Description : Bascule toute une chaîne de caractères en (min|maj)uscules. * +* * +* Retour : Pointeur sur la chaîne fournie. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *_make_string_xxx(char *str, int (* fn) (int)) +{ + size_t max; /* Empleur du parcours */ + size_t i; /* Boucle de parcours */ + + max = strlen(str); + + for (i = 0; i < max; i++) + str[i] = fn(str[i]); + + return str; + +} + + +/****************************************************************************** +* * +* Paramètres : raw = données brutes en provenance de l'analyseur. * +* details = indique la nature de la chaîne à traiter. * +* * +* Description : Traduit une chaîne en élément de fonction C. * +* * +* Retour : Chaîne à libérer de la mémoire après usage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *make_callable(const char *raw, bool details) +{ + char *result; /* Nom formaté à retourner */ + size_t max; /* Empleur du parcours */ + size_t i; /* Boucle de parcours */ + + result = strdup(raw); + + max = strlen(result); + + /* Première passe : on vire les virgules */ + + for (i = 0; i < max; i++) + if (result[i] == ',') + { + memmove(result + i, result + i + 1, max - i - 1); + max--; + } + + result[max] = '\0'; + + /* Deuxième passe : on bascule en minuscules */ + + result = make_string_lower(result); + + /* Troisième passe : on remplace les mauvais caractères */ + + for (i = 0; i < max; i++) + switch (result[i]) + { + case 'a' ... 'z': + case '0' ... '9': + break; + case '-': + result[i] = '_'; + break; + default: + result[i] = (i + 1 == max ? '\0' : '_'); + break; + } + + /** + * Dernière passe : on s'assure que le premier caractère n'est pas une lettre. + * On ajoute ici le préfixe '_' utilisé lors de la génération de prototypes ; + * en cas d'absence de détails, on ne se retrouve ainsi pas avec un '_' isolé. + */ + + if (details && result[0] != '_') + { + max = strlen(result) + 1; + result = (char *)realloc(result, max); + memmove(result + 1, result, max - 1); + result[0] = '_'; + } + + /* Ultime passe : supression des '_' groupés */ + + for (i = 0; i < max; i++) + if (result[i] == '_' && result[i + 1] == '_') + { + memmove(result + i + 1, result + i + 2, max - i - 1); + max--; + i--; + } + + return result; + +} diff --git a/tools/helpers.h b/tools/helpers.h new file mode 100644 index 0000000..8c39a85 --- /dev/null +++ b/tools/helpers.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers.h - prototypes pour les fonctionnalités d'assitance à la compilation + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_HELPERS_H +#define _TOOLS_HELPERS_H + + +#include <ctype.h> +#include <stdbool.h> + + + +/* ---------------------------- MANIPULATIONS DE CHAINES ---------------------------- */ + + +/* Bascule toute une chaîne de caractères en (min|maj)uscules. */ +char *_make_string_xxx(char *, int (* fn) (int)); + +#define make_string_lower(str) _make_string_xxx(str, tolower) +#define make_string_upper(str) _make_string_xxx(str, toupper) + +/* Traduit une chaîne en élément de fonction C. */ +char *make_callable(const char *raw, bool); + + + +#endif /* _TOOLS_HELPERS_H */ diff --git a/tools/macros.c b/tools/macros.c new file mode 100644 index 0000000..b1c44f0 --- /dev/null +++ b/tools/macros.c @@ -0,0 +1,167 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pproc.c - remplacements à la volée de chaînes de caractères + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "pproc.h" + + +#include <malloc.h> + + + + + + +/* Conversion des chaînes en chaînes */ +typedef struct _string_exch +{ + const char *src; /* Chaîne à trouver */ + const char *dest; /* Chaîne de remplacement */ + +} string_exch; + + +/* Pré-processeur avec support des macros */ +struct _pre_processor +{ + string_exch *macros; /* Remplacements de chaînes */ + size_t macros_count; /* Nombre de ces remplacements */ + + + +} + + + + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau suivi de l'encodage d'une instruction. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +encoding_spec *create_encoding_spec(void) +{ + encoding_spec *result; /* Définition vierge à renvoyer*/ + + result = (encoding_spec *)calloc(1, sizeof(encoding_spec)); + + result->bits = create_coding_bits(); + result->syntax = create_asm_syntax(); + result->conversions = create_conv_list(); + result->rules = create_decoding_rules(); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à libérer de la mémoire. * +* * +* Description : Supprime de la mémoire un suivi d'encodage d'une instruction.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_encoding_spec(encoding_spec *spec) +{ + delete_coding_bits(spec->bits); + delete_asm_syntax(spec->syntax); + delete_conv_list(spec->conversions); + delete_decoding_rules(spec->rules); + + free(spec); + +} + + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* src = chaîne à remplacer dans les définitions. * +* dest = chaîne de remplacement. * +* * +* Description : Constitue la matière d'un système de macros. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void define_macro_for_coder(rented_coder *coder, const char *src, const char *dest) +{ + string_exch *macro; /* Nouvelle macro à constituer */ + + coder->macros = (string_exch *)realloc(coder->macros, ++coder->macros_count * sizeof(string_exch)); + + macro = &coder->macros[coder->macros_count - 1]; + + macro->src = src; + macro->dest = dest; + +} + + +/****************************************************************************** +* * +* Paramètres : coder = gestion par la machine en remplacement de l'humain. * +* src = chaîne à remplacer dans les définitions. * +* * +* Description : Recherche l'existence d'une macro pour un remplacement. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const char *find_macro_in_coder(const rented_coder *coder, const char *src) +{ + const char *result; /* Trouvaille à renvoyer */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < coder->macros_count && result == NULL; i++) + if (strcmp(coder->macros[i].src, src) == 0) + result = coder->macros[i].dest; + + return result; + +} + + diff --git a/tools/macros.h b/tools/macros.h new file mode 100644 index 0000000..3755f00 --- /dev/null +++ b/tools/macros.h @@ -0,0 +1,30 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * macros.h - prototypes pour les remplacements à la volée de chaînes de caractères + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_MACROS_H +#define _TOOLS_MACROS_H + + + + +#endif /* _TOOLS_MACROS_H */ diff --git a/tools/pproc.c b/tools/pproc.c new file mode 100644 index 0000000..8644af5 --- /dev/null +++ b/tools/pproc.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pproc.c - remplacements à la volée de chaînes de caractères + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "pproc.h" + + +#include <malloc.h> +#include <string.h> + + + +/* Pré-processeur avec support des macros */ +struct _pre_processor +{ + string_exch *encodings; /* Traductions d'encodages */ + size_t encodings_count; /* Nombre de ces traductions */ + + string_exch *macros; /* Remplacements de chaînes */ + size_t macros_count; /* Nombre de ces remplacements */ + +}; + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau pre-processeur pour le support des macros. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +pre_processor *create_pre_processor(void) +{ + pre_processor *result; /* Définition vierge à renvoyer*/ + + result = (pre_processor *)calloc(1, sizeof(pre_processor)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : pp = pré-processeur à libérer de la mémoire. * +* * +* Description : Supprime de la mémoire un pré-processeur et ses macros. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_pre_processor(pre_processor *pp) +{ + if (pp->encodings != NULL) + free(pp->encodings); + + if (pp->macros != NULL) + free(pp->macros); + + free(pp); + +} + + +/****************************************************************************** +* * +* Paramètres : pp = pré-processeur dont le contenu est à compléter. * +* src = chaîne à remplacer dans les définitions. * +* dest = chaîne de remplacement. * +* * +* Description : Enregistre une correspondance en matière d'encodage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_encoding(pre_processor *pp, const char *src, const char *dest) +{ + string_exch *encoding; /* Traduction à conserver */ + + pp->encodings = (string_exch *)realloc(pp->encodings, ++pp->encodings_count * sizeof(string_exch)); + + encoding = &pp->encodings[pp->encodings_count - 1]; + + encoding->src = src; + encoding->dest = dest; + +} + + +/****************************************************************************** +* * +* Paramètres : pp = pré-processeur dont le contenu est à consulter. * +* * +* Description : Indique le nombre de catégories d'encodages enregistrées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t count_encodings(const pre_processor *pp) +{ + return pp->encodings_count; + +} + + +/****************************************************************************** +* * +* Paramètres : pp = pré-processeur dont le contenu est à consulter. * +* index = indice de l'encodage à retourner. * +* * +* Description : Fournit une catégorie d'encodage donnée. * +* * +* Retour : Correspondance à consulter uniquement. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const string_exch *find_encoding(const pre_processor *pp, size_t index) +{ + return &pp->encodings[index]; + +} + + +/****************************************************************************** +* * +* Paramètres : pp = pré-processeur dont le contenu est à compléter. * +* src = chaîne à remplacer dans les définitions. * +* dest = chaîne de remplacement. * +* * +* Description : Constitue la matière d'un système de macros. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void define_macro(pre_processor *pp, const char *src, const char *dest) +{ + string_exch *macro; /* Nouvelle macro à constituer */ + + pp->macros = (string_exch *)realloc(pp->macros, ++pp->macros_count * sizeof(string_exch)); + + macro = &pp->macros[pp->macros_count - 1]; + + macro->src = src; + macro->dest = dest; + +} + + +/****************************************************************************** +* * +* Paramètres : pp = pré-processeur dont le contenu est à consulter. * +* src = chaîne à remplacer dans les définitions. * +* * +* Description : Recherche l'existence d'une macro pour un remplacement. * +* * +* Retour : Eventuelle correspondance trouvée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *find_macro(const pre_processor *pp, const char *src) +{ + const char *result; /* Trouvaille à renvoyer */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < pp->macros_count && result == NULL; i++) + if (strcmp(pp->macros[i].src, src) == 0) + result = pp->macros[i].dest; + + return result; + +} diff --git a/tools/pproc.h b/tools/pproc.h new file mode 100644 index 0000000..6675fa1 --- /dev/null +++ b/tools/pproc.h @@ -0,0 +1,67 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pproc.h - prototypes pour les remplacements à la volée de chaînes de caractères + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_PPROC_H +#define _TOOLS_PPROC_H + + +#include <sys/types.h> + + + +/* Conversion des chaînes en chaînes */ +typedef struct _string_exch +{ + const char *src; /* Chaîne à trouver */ + const char *dest; /* Chaîne de remplacement */ + +} string_exch; + +/* Pré-processeur avec support des macros */ +typedef struct _pre_processor pre_processor; + + +/* Crée un nouveau pre-processeur pour le support des macros. */ +pre_processor *create_pre_processor(void); + +/* Supprime de la mémoire un pré-processeur et ses macros. */ +void delete_pre_processor(pre_processor *); + +/* Enregistre une correspondance en matière d'encodage. */ +void register_encoding(pre_processor *, const char *, const char *); + +/* Indique le nombre de catégories d'encodages enregistrées. */ +size_t count_encodings(const pre_processor *); + +/* Fournit une catégorie d'encodage donnée. */ +const string_exch *find_encoding(const pre_processor *, size_t); + +/* Constitue la matière d'un système de macros. */ +void define_macro(pre_processor *, const char *, const char *); + +/* Recherche l'existence d'une macro pour un remplacement. */ +const char *find_macro(const pre_processor *, const char *); + + + +#endif /* _TOOLS_PPROC_H */ diff --git a/tools/rules.c b/tools/rules.c new file mode 100644 index 0000000..25ba76c --- /dev/null +++ b/tools/rules.c @@ -0,0 +1,439 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rules.h - prototypes pour les variations de décodage selon certaines conditions + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "rules.h" + + +#include <malloc.h> +#include <stdbool.h> +#include <string.h> + + +#include "helpers.h" + + + +/* -------------------------- CONDITIONS DE DECLENCHEMENTS -------------------------- */ + + +/* Expression d'une condition */ +struct _cond_expr +{ + bool is_simple; /* Sélection de champ */ + + union + { + struct + { + char *variable; /* Variable manipulée */ + CondCompType comp; /* Type de comparaison */ + char *bvalue; /* Valeur binaire comparée */ + + } simple; + + struct + { + cond_expr *a; /* Première sous-expression */ + CondOpType operator; /* Relation entre expressions */ + cond_expr *b; /* Seconde sous-expression */ + + } composed; + + }; + +}; + + +/* Libère de la mémoire une expression conditionnelle. */ +static void delete_cond_expr(cond_expr *); + +/* Traduit en code une expression de condition. */ +static bool write_cond_expr(const cond_expr *, int, const coding_bits *); + + + +/* ------------------------- REGLES ET ACTIONS CONSEQUENTES ------------------------- */ + + +/* Règle particulière */ +typedef struct _extra_rule +{ + cond_expr *expr; /* Expression de déclenchement */ + CondActionType action; /* Conséquence d'une validation*/ + char *details; /* Eventuel complément d'info. */ + +} extra_rule; + +/* Règles de décodage supplémentaires */ +struct _decoding_rules +{ + extra_rule *extra; /* Règles conditionnelles */ + size_t extra_count; /* Nombre de ces règles */ + +}; + + + +/* ---------------------------------------------------------------------------------- */ +/* CONDITIONS DE DECLENCHEMENTS */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : variable = désignation de la variable à manipuler. * +* comp = type de comparaison à utiliser. * +* bvalue = valeur binaire à comparer. * +* * +* Description : Crée une expression conditionnelle simple. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cond_expr *build_simple_cond_expression(char *variable, CondCompType comp, char *bvalue) +{ + cond_expr *result; /* Structure à retourner */ + + result = (cond_expr *)calloc(1, sizeof(cond_expr)); + + result->is_simple = true; + + result->simple.variable = make_string_lower(variable); + result->simple.comp = comp; + result->simple.bvalue = bvalue; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = première expression à intégrer. * +* operator = type de comparaison à utiliser. * +* b = second expression à intégrer. * +* * +* Description : Crée une expression conditionnelle composée. * +* * +* Retour : Structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +cond_expr *build_composed_cond_expression(cond_expr *a, CondOpType operator, cond_expr *b) +{ + cond_expr *result; /* Structure à retourner */ + + result = (cond_expr *)calloc(1, sizeof(cond_expr)); + + result->is_simple = false; + + result->composed.a = a; + result->composed.operator = operator; + result->composed.b = b; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : expr = représentation d'expression à traiter. * +* * +* Description : Libère de la mémoire une expression conditionnelle. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_cond_expr(cond_expr *expr) +{ + if (expr->is_simple) + { + free(expr->simple.variable); + free(expr->simple.bvalue); + } + else + { + delete_cond_expr(expr->composed.a); + delete_cond_expr(expr->composed.b); + } + + free(expr); + +} + + +/****************************************************************************** +* * +* Paramètres : expr = expression simple ou composée à transposer. * +* fd = descripteur d'un flux ouvert en écriture. * +* bits = gestionnaire des bits d'encodage. * +* * +* Description : Traduit en code une expression de condition. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool write_cond_expr(const cond_expr *expr, int fd, const coding_bits *bits) +{ + bool result; /* Bilan à renvoyer */ + const raw_bitfield *bf; /* Champ de bits de définition */ + + result = true; + + dprintf(fd, "("); + + if (expr->is_simple) + { + bf = find_named_field_in_bits(bits, expr->simple.variable); + if (bf == NULL) + { + fprintf(stderr, "Error: no bitfield defined the requested variable '%s'.\n", expr->simple.variable); + result = false; + goto wce_exit; + } + + if (get_raw_bitfield_length(bf) != strlen(expr->simple.bvalue)) + { + fprintf(stderr, "Error: variable '%s' and provided value sizes do not match (%u vs %zu).\n", + expr->simple.variable, get_raw_bitfield_length(bf), strlen(expr->simple.bvalue)); + result = false; + goto wce_exit; + } + + dprintf(fd, "raw_%s", expr->simple.variable); + + switch (expr->simple.comp) + { + case CCT_EQUAL: + dprintf(fd, " == "); + break; + case CCT_DIFF: + dprintf(fd, " != "); + break; + } + + dprintf(fd, "b%s", expr->simple.bvalue); + + } + else + { + result = write_cond_expr(expr->composed.a, fd, bits); + if (!result) goto wce_exit; + + switch (expr->composed.operator) + { + case COT_AND: + dprintf(fd, " && "); + break; + case COT_OR: + dprintf(fd, " || "); + break; + } + + result = write_cond_expr(expr->composed.b, fd, bits); + if (!result) goto wce_exit; + + } + + dprintf(fd, ")"); + + wce_exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* REGLES ET ACTIONS CONSEQUENTES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau rassemblement de règles de décodage. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +decoding_rules *create_decoding_rules(void) +{ + decoding_rules *result; /* Définition vierge à renvoyer*/ + + result = (decoding_rules *)calloc(1, sizeof(decoding_rules)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : rules = ensemble de règles de décodage à supprimer. * +* * +* Description : Supprime de la mémoire un ensemble de règles supplémentaires.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_decoding_rules(decoding_rules *rules) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < rules->extra_count; i++) + { + delete_cond_expr(rules->extra[i].expr); + if (rules->extra[i].details) + free(rules->extra[i].details); + } + + if (rules->extra != NULL) + free(rules->extra); + + free(rules); + +} + + +/****************************************************************************** +* * +* Paramètres : rules = ensemble de règles à compléter. * +* expr = représentation d'expression à conserver. * +* action = conséquence associée à la règle. * +* details = éventuel complément d'informations. * +* * +* Description : Ajoute une règle complète à la définition d'un codage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_conditional_rule(decoding_rules *rules, cond_expr *expr, CondActionType action, const char *details) +{ + extra_rule *rule; /* Nouvelle prise en compte */ + + rules->extra = (extra_rule *)realloc(rules->extra, ++rules->extra_count * sizeof(extra_rule)); + + rule = &rules->extra[rules->extra_count - 1]; + + rule->expr = expr; + rule->action = action; + rule->details = (details != NULL ? make_callable(details, false) : NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : rules = ensemble de règles à consulter. * +* fd = descripteur d'un flux ouvert en écriture. * +* bits = gestionnaire des bits d'encodage. * +* exit = exprime le besoin d'une voie de sortie. [OUT] * +* * +* Description : Traduit en code les éventuelles règles présentes. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool write_decoding_rules(decoding_rules *rules, int fd, const coding_bits *bits, bool *exit) +{ + bool result; /* Bilan à remonter */ + const extra_rule *rule; /* Règle en cours d'écriture */ + size_t i; /* Boucle de parcours */ + + result = true; + + *exit = false; + + for (i = 0; i < rules->extra_count; i++) + { + rule = &rules->extra[i]; + + dprintf(fd, "\t\tif "); + + result = write_cond_expr(rule->expr, fd, bits); + if (!result) break; + + dprintf(fd, "\n"); + dprintf(fd, "\t\t{\n"); + + switch (rule->action) + { + case CAT_SEE: + + if (rule->details == NULL) + { + fprintf(stderr, "Error: directive 'see' must provide additional details.\n"); + result = false; + goto wcsr_exit; + } + + dprintf(fd, "\t\t\tinstr = armv7_read_instr_%s", rule->details); + + /* TODO : adapter les paramètres d'appel selon le 'coder' */ + dprintf(fd, "(_raw);\n"); + + dprintf(fd, "\t\t\tgoto quick_exit;\n"); + + *exit = true; + break; + + } + + dprintf(fd, "\t\t}\n"); + + dprintf(fd, "\n"); + + } + + wcsr_exit: + + return result; + +} diff --git a/tools/rules.h b/tools/rules.h new file mode 100644 index 0000000..a4a9bb4 --- /dev/null +++ b/tools/rules.h @@ -0,0 +1,91 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rules.h - prototypes pour les variations de décodage selon certaines conditions + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_RULES_H +#define _TOOLS_RULES_H + + +#include "bits.h" + + + +/* -------------------------- CONDITIONS DE DECLENCHEMENTS -------------------------- */ + + +/* Types de comparaison */ +typedef enum _CondCompType +{ + CCT_EQUAL, /* Egalité '==' */ + CCT_DIFF /* Différence '!=' */ + +} CondCompType; + +/* Types de combinaison d'expressions */ +typedef enum _CondOpType +{ + COT_AND, /* Combinaison ET ('&&') */ + COT_OR /* Combinaison OU ('||') */ + +} CondOpType; + +/* Expression d'une condition */ +typedef struct _cond_expr cond_expr; + + +/* Crée une expression conditionnelle simple. */ +cond_expr *build_simple_cond_expression(char *, CondCompType, char *); + +/* Crée une expression conditionnelle composée. */ +cond_expr *build_composed_cond_expression(cond_expr *, CondOpType, cond_expr *); + + + +/* ------------------------- REGLES ET ACTIONS CONSEQUENTES ------------------------- */ + + +/* Conséquence en cas de condition remplie */ +typedef enum _CondActionType +{ + CAT_SEE /* Renvoi vers une instruction */ + +} CondActionType; + +/* Règles de décodage supplémentaires */ +typedef struct _decoding_rules decoding_rules; + + +/* Crée un nouveau rassemblement de règles de décodage. */ +decoding_rules *create_decoding_rules(void); + +/* Supprime de la mémoire un ensemble de règles supplémentaires. */ +void delete_decoding_rules(decoding_rules *); + +/* Ajoute une règle complète à la définition d'un codage. */ +void register_conditional_rule(decoding_rules *, cond_expr *, CondActionType, const char *); + +/* Traduit en code les éventuelles règles présentes. */ +bool write_decoding_rules(decoding_rules *, int, const coding_bits *, bool *); + + + +#endif /* _TOOLS_RULES_H */ diff --git a/tools/spec.c b/tools/spec.c new file mode 100644 index 0000000..a957587 --- /dev/null +++ b/tools/spec.c @@ -0,0 +1,349 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * spec.c - représentation complète d'un encodage + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "spec.h" + + +#include <malloc.h> +#include <regex.h> +#include <string.h> + + +#include "helpers.h" + + + + + +#define get_raw_bitfield_name(bf) "" + + + + + +#define get_syntax_item_name(si) "" + + + + + + + +/* Mémorisation d'un encodage complet */ +struct _encoding_spec +{ + char *prefix; /* Distinction principale */ + unsigned int index; /* Distinction secondaire */ + + coding_bits *bits; /* Encodage des bits associés */ + asm_syntax *syntax; /* Calligraphe d'assemblage */ + conv_list *conversions; /* Conversions des données */ + decoding_rules *rules; /* Règles supplémentaires */ + +}; + + + + + + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau suivi de l'encodage d'une instruction. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +encoding_spec *create_encoding_spec(void) +{ + encoding_spec *result; /* Définition vierge à renvoyer*/ + + result = (encoding_spec *)calloc(1, sizeof(encoding_spec)); + + result->bits = create_coding_bits(); + result->syntax = create_asm_syntax(); + result->conversions = create_conv_list(); + result->rules = create_decoding_rules(); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à libérer de la mémoire. * +* * +* Description : Supprime de la mémoire un suivi d'encodage d'une instruction.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_encoding_spec(encoding_spec *spec) +{ + delete_coding_bits(spec->bits); + delete_asm_syntax(spec->syntax); + delete_conv_list(spec->conversions); + delete_decoding_rules(spec->rules); + + free(spec); + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à compléter. * +* prefix = distinction principale entre les définitions. * +* index = distinction secondaire entre les définitions. * +* * +* Description : Définit le nom de code d'une spécification d'encodage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void define_encoding_spec_code_name(encoding_spec *spec, char *prefix, unsigned int index) +{ + spec->prefix = prefix; + spec->index = index; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à consulter. * +* prefix = distinction principale entre les définitions. * +* * +* Description : Indique si une spécification se range dans une catégorie. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool has_encoding_spec_prefix(const encoding_spec *spec, const char *prefix) +{ + return (strcmp(spec->prefix, prefix) == 0); + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à consulter. * +* * +* Description : Fournit le gestionnaire des bits d'un encodage d'instruction.* +* * +* Retour : Structure assurant le suivi des bits. * +* * +* Remarques : - * +* * +******************************************************************************/ + +coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec) +{ + return spec->bits; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à consulter. * +* * +* Description : Fournit l'indicateur des écritures correctes d'assembleur. * +* * +* Retour : Structure assurant la gestion des éléments de syntaxe. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec) +{ + return spec->syntax; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à 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_spec(const encoding_spec *spec) +{ + return spec->conversions; + +} + + +/****************************************************************************** +* * +* Paramètres : spec = spécification d'encodage à 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_spec(const encoding_spec *spec) +{ + return spec->rules; + +} + + +/****************************************************************************** +* * +* 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. * +* ins = désignation première de l'instruction manipulée. * +* details = particularités de l'instruction. * +* keyword = nom clef de l'instruction utilisable dans du code. * +* wide = taille des mots manipulés (en bits). * +* pp = pré-processeur pour les échanges de chaînes. * +* * +* Description : Traduit en code une sous-fonction de désassemblage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *arch, const char *ins, const char *details, unsigned int wide, const pre_processor *pp) +{ + bool result; /* Bilan à retourner */ + char *keyword; /* Mot clef appelable en code */ + bool exit; /* Inclusion de sortie rapide ?*/ + + result = true; + + keyword = make_callable(ins, false); + + dprintf(fd, "\tGArchInstruction *%s_decode_%s%s_%s%u(uint%u_t _raw)\n", + arch, keyword, details, spec->prefix, spec->index, wide); + + dprintf(fd, "\t{\n"); + + dprintf(fd, "\t\tGArchInstruction *instr;\n"); + + /* Déclaration des champs à retrouver */ + + result &= mark_syntax_items(spec->syntax, spec->bits, spec->conversions); + + result &= declare_used_bits_fields(spec->bits, fd, wide); + + result &= declare_syntax_items(spec->syntax, fd, spec->bits, spec->conversions, wide); + + dprintf(fd, "\n"); + + /* Vérification que le décodage est possible */ + + result &= check_bits_correctness(spec->bits, fd); + + dprintf(fd, "\n"); + + /* Définition des champs bruts */ + + result &= define_used_bits_fields(spec->bits, fd); + + dprintf(fd, "\n"); + + /* Inclusion des éventuelles règles */ + + result &= write_decoding_rules(spec->rules, fd, spec->bits, &exit); + + /* Création de l'instruction en elle-même */ + + dprintf(fd, "\t\tinstr = g_%s_instruction_new(\"%s\");\n", arch, ins); + + dprintf(fd, "\n"); + + /* Création des opérandes */ + + result &= define_syntax_items(spec->syntax, fd, arch, spec->bits, spec->conversions, pp); + + /* Conclusion de la procédure */ + + if (exit) + { + dprintf(fd, "\t quick_exit:\n"); + dprintf(fd, "\n"); + } + + dprintf(fd, "\t\treturn instr;\n"); + + dprintf(fd, "\n"); + + dprintf(fd, "\t bad_exit:\n"); + + dprintf(fd, "\n"); + + dprintf(fd, "\t\tg_object_unref(G_OBJECT(instr));\n"); + dprintf(fd, "\t\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->prefix, spec->index); + + dprintf(fd, "\n"); + + free(keyword); + + return result; + +} diff --git a/tools/spec.h b/tools/spec.h new file mode 100644 index 0000000..46d922b --- /dev/null +++ b/tools/spec.h @@ -0,0 +1,72 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * spec.h - prototypes pour la représentation complète d'un encodage + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_SPEC_H +#define _TOOLS_SPEC_H + + +#include <stdbool.h> + + +#include "bits.h" +#include "conv.h" +#include "pproc.h" +#include "rules.h" +#include "syntax.h" + + + +/* Mémorisation d'un encodage complet */ +typedef struct _encoding_spec encoding_spec; + + +/* Crée un nouveau suivi de l'encodage d'une instruction. */ +encoding_spec *create_encoding_spec(void); + +/* Supprime de la mémoire un suivi d'encodage d'une instruction. */ +void delete_encoding_spec(encoding_spec *); + +/* Définit le nom de code d'une spécification d'encodage. */ +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 *); + +/* 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 un ensemble de règles supplémentaires éventuel. */ +decoding_rules *get_rules_in_encoding_spec(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 *, unsigned int, const pre_processor *); + + + +#endif /* _TOOLS_SPEC_H */ diff --git a/tools/syntax.c b/tools/syntax.c new file mode 100644 index 0000000..5fec1a6 --- /dev/null +++ b/tools/syntax.c @@ -0,0 +1,321 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * syntax.c - prise en compte d'une syntaxe du langage d'assemblage + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "syntax.h" + + +#include <malloc.h> +#include <string.h> + + +#include "helpers.h" + + + +/* Propriétés particulières pour les opérandes */ +typedef enum _SyntaxItemFlags +{ + SIF_NONE = (0 << 0), /* Aucune propriété */ + SIF_DECIMAL = (1 << 0) /* Affichage en décimal */ + +} SyntaxItemFlags; + +/* Elément défini dans une syntaxe */ +typedef struct _syntax_item +{ + char *name; /* Désignation humaine */ + bool internal; /* Enregistrement générique ? */ + SyntaxItemFlags flags; /* Propriétés supplémentaires */ + +} syntax_item; + +/* Syntaxe d'une ligne d'assembleur */ +struct _asm_syntax +{ + syntax_item *items; /* Eléments de la syntaxe */ + size_t items_count; /* Nombre de ces éléments */ + +}; + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouvel indicateur pour l'écriture d'une instruction. * +* * +* Retour : Nouvelle structure prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +asm_syntax *create_asm_syntax(void) +{ + asm_syntax *result; /* Définition vierge à renvoyer*/ + + result = (asm_syntax *)calloc(1, sizeof(asm_syntax)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* * +* Description : Supprime de la mémoire un indicateur d'écriture ASM. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void delete_asm_syntax(asm_syntax *syntax) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < syntax->items_count; i++) + free(syntax->items[i].name); + + if (syntax->items != NULL) + free(syntax->items); + + free(syntax); + +} + + +/****************************************************************************** +* * +* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. * +* name = désignation de l'opérande dans la spécification. * +* internal = précise si l'opérand est non générique ou non. * +* * +* Description : Enregistre la présence d'un nouvel opérande dans la syntaxe. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void register_syntax_item(asm_syntax *syntax, char *name, bool internal) +{ + 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)); + + item = &syntax->items[syntax->items_count - 1]; + + /* Récupération des drapeaux */ + + item->flags = SIF_NONE; + + for (len = strlen(name); len > 0; len--) + switch (name[0]) + { + case '#': + item->flags |= SIF_DECIMAL; + memmove(name, name + 1, len); + break; + + default: + len = 1; + break; + + } + + item->name = make_string_lower(name); + item->internal = internal; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Description : Marque les champs de bits effectivement utilisés. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const conv_list *list) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + syntax_item *item; /* Lien vers un opérande */ + conv_func *func; /* Fonction de conversion */ + + result = true; + + for (i = 0; i < syntax->items_count && result; i++) + { + item = &syntax->items[i]; + + func = find_named_conv_in_list(list, item->name); + if (func == NULL) + { + fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name); + result = false; + } + + result = mark_conv_func(func, bits, list); + + } + + 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. * +* list = liste de l'ensemble des fonctions de conversion. * +* wide = taille des mots décodés. * +* * +* Description : Déclare les variables C associées aux opérandes de syntaxe. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide) +{ + bool result; /* Bilan à retourner */ + bool has_operand; /* Présence d'un opérande */ + 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; + + for (i = 0; i < syntax->items_count && result; i++) + { + item = &syntax->items[i]; + + has_operand |= !item->internal; + + func = find_named_conv_in_list(list, item->name); + if (func == NULL) + { + fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name); + result = false; + } + + result &= declare_conv_func(func, fd, bits, list, wide); + + } + + if (has_operand) + dprintf(fd, "\t\tGArchOperand *op;\n"); + + 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. * +* list = liste de l'ensemble des fonctions de conversion. * +* pp = pré-processeur pour les échanges de chaînes. * +* * +* Description : Définit les variables C associées aux opérandes de syntaxe. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +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 result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + syntax_item *item; /* Lien vers un opérande */ + conv_func *func; /* Fonction de conversion */ + + result = true; + + for (i = 0; i < syntax->items_count && result; i++) + { + item = &syntax->items[i]; + + func = find_named_conv_in_list(list, item->name); + if (func == NULL) + { + fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name); + result = false; + } + + /* Appel proprement dit */ + + result &= define_conv_func(func, true, item->internal, fd, arch, bits, list, pp); + if (!result) break; + + /* Raccordement : propriété ou opérande ? */ + + if (item->internal) + dprintf(fd, "\t\t\tgoto bad_exit;\n"); + + else + { + dprintf(fd, "\t\tif (op == NULL) goto bad_exit;\n"); + + dprintf(fd, "\n"); + + if (item->flags & SIF_DECIMAL) + dprintf(fd, "\t\tg_imm_operand_set_display(G_IMM_OPERAND(op), IOD_DEC);\n"); + + dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n"); + + } + + dprintf(fd, "\n"); + + } + + return result; + +} diff --git a/tools/syntax.h b/tools/syntax.h new file mode 100644 index 0000000..0cd9210 --- /dev/null +++ b/tools/syntax.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * syntax.h - prototypes pour la prise en compte d'une syntaxe du langage d'assemblage + * + * Copyright (C) 2014 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenIDA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _TOOLS_SYNTAX_H +#define _TOOLS_SYNTAX_H + + +#include <stdbool.h> + + +#include "bits.h" +#include "conv.h" +#include "pproc.h" + + + +/* Syntaxe d'une ligne d'assembleur */ +typedef struct _asm_syntax asm_syntax; + + +/* Crée un nouvel indicateur pour l'écriture d'une instruction. */ +asm_syntax *create_asm_syntax(void); + +/* Supprime de la mémoire un indicateur d'écriture ASM. */ +void delete_asm_syntax(asm_syntax *); + +/* Enregistre la présence d'un nouvel opérande dans la syntaxe. */ +void register_syntax_item(asm_syntax *, char *, bool); + +/* Marque les champs de bits effectivement utilisés. */ +bool mark_syntax_items(const asm_syntax *, 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); + +/* 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 *); + + + +#endif /* _TOOLS_SYNTAX_H */ |