diff options
| -rw-r--r-- | ChangeLog | 53 | ||||
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | src/analysis/disass/fetch.c | 4 | ||||
| -rw-r--r-- | src/arch/arm/instruction.c | 8 | ||||
| -rw-r--r-- | src/arch/arm/instruction.h | 4 | ||||
| -rw-r--r-- | src/arch/arm/v7/Makefile.am | 6 | ||||
| -rw-r--r-- | src/arch/arm/v7/arm.c | 3 | ||||
| -rw-r--r-- | src/arch/arm/v7/helpers.c | 58 | ||||
| -rw-r--r-- | src/arch/arm/v7/helpers.h | 40 | ||||
| -rw-r--r-- | src/arch/arm/v7/instruction.c | 10 | ||||
| -rw-r--r-- | src/arch/arm/v7/instruction.h | 7 | ||||
| -rw-r--r-- | src/arch/arm/v7/opcodes/Makefile.am | 15 | ||||
| -rw-r--r-- | src/arch/arm/v7/opdefs/Makefile.am | 37 | ||||
| -rw-r--r-- | src/arch/arm/v7/opdefs/mov_A88104.d | 47 | ||||
| -rw-r--r-- | src/arch/arm/v7/opdefs/subs_B9320.d | 44 | ||||
| -rw-r--r-- | src/arch/arm/v7/processor.c | 12 | ||||
| -rw-r--r-- | src/arch/register-int.h | 29 | ||||
| -rw-r--r-- | src/arch/register.c | 202 | ||||
| -rw-r--r-- | src/arch/register.h | 39 | ||||
| -rw-r--r-- | tools/Makefile.am | 25 | ||||
| -rw-r--r-- | tools/coder.c | 1878 | ||||
| -rw-r--r-- | tools/coder.h | 158 | ||||
| -rw-r--r-- | tools/d2c.mk | 22 | ||||
| -rw-r--r-- | tools/d2c_gram.y | 329 | ||||
| -rw-r--r-- | tools/d2c_tok.l | 165 | 
26 files changed, 3184 insertions, 16 deletions
@@ -1,3 +1,56 @@ +14-10-08  Cyrille Bagard <nocbos@gmail.com> + +	* configure.ac: +	Add the new Makefiles from the 'src/arch/arm/v7/opdefs', +	'src/arch/arm/v7/opcodes' and 'tools' directories. + +	* Makefile.am: +	Add the 'tools' directory to SUBDIRS. + +	* src/analysis/disass/fetch.c: +	Add some debug code. + +	* src/arch/arm/instruction.c: +	* src/arch/arm/instruction.h: +	Fix mistakes: some functions need to return a status boolean. + +	* src/arch/arm/v7/arm.c: +	Update code. + +	* src/arch/arm/v7/helpers.c: +	* src/arch/arm/v7/helpers.h: +	New entries: translate pseudo functions of the ARM instruction specifications. + +	* src/arch/arm/v7/instruction.c: +	* src/arch/arm/v7/instruction.h: +	Fix mistakes: some functions need to return a status boolean. + +	* src/arch/arm/v7/Makefile.am: +	Add the 'helpers.[ch]' files to libarcharmv7_la_SOURCES and +	'opcodes/libarcharmv7opcodes.la' to libarcharmv7_la_LIBADD. + +	* src/arch/arm/v7/opcodes/Makefile.am: +	* src/arch/arm/v7/opdefs/Makefile.am: +	* src/arch/arm/v7/opdefs/mov_A88104.d: +	* src/arch/arm/v7/opdefs/subs_B9320.d: +	New entries: generate code for the support of two first ARMv7 instructions. + +	* src/arch/arm/v7/processor.c: +	Update code. + +	* src/arch/register.c: +	* src/arch/register.h: +	* src/arch/register-int.h: +	Define generic register operands. + +	* tools/coder.c: +	* tools/coder.h: +	* tools/d2c_gram.y: +	* tools/d2c.mk: +	* tools/d2c_tok.l: +	* tools/Makefile.am: +	New entries: create a compiler for architecture instruction definitions. +  14-10-06  Cyrille Bagard <nocbos@gmail.com>  	* src/analysis/disass/fetch.c: diff --git a/Makefile.am b/Makefile.am index 31d97d0..7357b00 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,6 +11,6 @@ revision.h: .svn  EXTRA_DIST = config.rpath  ChangeLog -SUBDIRS = pixmaps src plugins po themes +SUBDIRS = tools pixmaps src plugins po themes  ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 3534c4f..4f900ac 100644 --- a/configure.ac +++ b/configure.ac @@ -306,6 +306,8 @@ AC_CONFIG_FILES([Makefile                   src/arch/Makefile                   src/arch/arm/Makefile                   src/arch/arm/v7/Makefile +                 src/arch/arm/v7/opdefs/Makefile +                 src/arch/arm/v7/opcodes/Makefile                   src/arch/dalvik/Makefile                   src/arch/dalvik/decomp/Makefile                   src/arch/dalvik/opcodes/Makefile @@ -348,6 +350,7 @@ AC_CONFIG_FILES([Makefile                   src/panels/Makefile                   src/plugins/Makefile                   src/plugins/overjump/Makefile +                 tools/Makefile                   themes/Makefile])  AC_OUTPUT diff --git a/src/analysis/disass/fetch.c b/src/analysis/disass/fetch.c index 97cad33..eee2eb6 100644 --- a/src/analysis/disass/fetch.c +++ b/src/analysis/disass/fetch.c @@ -159,6 +159,8 @@ static GArchInstruction *load_code_binary(const GLoadedBinary *binary, const vmp      {          instr = g_arch_processor_disassemble(proc, NULL, bin_data, &pos, end); +        if (!G_IS_RAW_INSTRUCTION(instr)) printf("GOT %p\n", instr); +          if (instr == NULL)          instr = g_raw_instruction_new_array(bin_data, MDS_32_BITS, 1, &pos, end,                                              g_arch_processor_get_endianness(proc)); @@ -294,7 +296,7 @@ GArchInstruction *disassemble_binary_content(const GLoadedBinary *binary, GtkExt          /* Traiter la diff */ -        if (cmp_vmpa_by_phy(last, border) < 0) +        if (0 && cmp_vmpa_by_phy(last, border) < 0)          {              joint = load_raw_binary(binary, last,                                      get_phy_addr(last) + compute_vmpa_diff(border, last), diff --git a/src/arch/arm/instruction.c b/src/arch/arm/instruction.c index c315bae..b46cab0 100644 --- a/src/arch/arm/instruction.c +++ b/src/arch/arm/instruction.c @@ -46,7 +46,7 @@ static const char *g_arm_instruction_get_keyword(const GArmInstruction *, AsmSyn  /* Indique le type défini pour une représentation d'une instruction ARM. */ -G_DEFINE_TYPE(GArmInstruction, g_arm_instruction, G_TYPE_ARM_INSTRUCTION); +G_DEFINE_TYPE(GArmInstruction, g_arm_instruction, G_TYPE_ARCH_INSTRUCTION);  /****************************************************************************** @@ -160,16 +160,18 @@ static const char *g_arm_instruction_get_keyword(const GArmInstruction *instr, A  *                                                                             *  *  Description : Définit les conditions d'exécution d'une instruction ARM.    *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_arm_instruction_set_cond(GArmInstruction *instr, ArmCondCode cond) +bool g_arm_instruction_set_cond(GArmInstruction *instr, ArmCondCode cond)  {      instr->cond = cond; +    return true; +  } diff --git a/src/arch/arm/instruction.h b/src/arch/arm/instruction.h index ecd9919..3211766 100644 --- a/src/arch/arm/instruction.h +++ b/src/arch/arm/instruction.h @@ -26,10 +26,12 @@  #include <glib-object.h> +#include <stdbool.h>  #include <stdint.h>  #include "cond.h" +#include "../instruction.h" @@ -52,7 +54,7 @@ typedef struct _GArmInstructionClass GArmInstructionClass;  GType g_arm_instruction_get_type(void);  /* Définit les conditions d'exécution d'une instruction ARM. */ -void g_arm_instruction_set_cond(GArmInstruction *, ArmCondCode); +bool g_arm_instruction_set_cond(GArmInstruction *, ArmCondCode);  /* Indique les conditions d'exécution d'une instruction ARM. */  ArmCondCode g_arm_instruction_get_cond(const GArmInstruction *); diff --git a/src/arch/arm/v7/Makefile.am b/src/arch/arm/v7/Makefile.am index dc095ed..3fe1394 100644 --- a/src/arch/arm/v7/Makefile.am +++ b/src/arch/arm/v7/Makefile.am @@ -3,10 +3,14 @@ noinst_LTLIBRARIES = libarcharmv7.la  libarcharmv7_la_SOURCES =				\  	arm.h arm.c							\ +	helpers.h helpers.c					\  	instruction.h instruction.c			\  	processor.h processor.c				\  	register.h register.c +libarcharmv7_la_LIBADD =				\ +	opcodes/libarcharmv7opcodes.la +  libarcharmv7_la_CFLAGS = $(AM_CFLAGS) @@ -15,4 +19,4 @@ AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS)  AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) -SUBDIRS = #opdefs +SUBDIRS = opdefs opcodes diff --git a/src/arch/arm/v7/arm.c b/src/arch/arm/v7/arm.c index 4953b6b..bd1beb8 100644 --- a/src/arch/arm/v7/arm.c +++ b/src/arch/arm/v7/arm.c @@ -27,6 +27,7 @@  #include <stdint.h> +#include "opcodes/opcodes.h"  #include "../../../common/bconst.h" @@ -82,7 +83,7 @@ static GArchInstruction *process_armv7_data_processing_register(uint32_t);  #define armv7_read_instr_cmp_register(raw) NULL  #define armv7_read_instr_cmn_register(raw) NULL  #define armv7_read_instr_orr_register(raw) NULL -#define armv7_read_instr_mov_register_arm(raw) NULL +//#define armv7_read_instr_mov_register_arm(raw) NULL  #define armv7_read_instr_lsl_immediate(raw) NULL  #define armv7_read_instr_lsr_immediate(raw) NULL  #define armv7_read_instr_asr_immediate(raw) NULL diff --git a/src/arch/arm/v7/helpers.c b/src/arch/arm/v7/helpers.c new file mode 100644 index 0000000..632c1b7 --- /dev/null +++ b/src/arch/arm/v7/helpers.c @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers.c - aide à la mise en place des opérandes ARMv7 + * + * 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 "register.h" +#include "../../register.h" + + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : index = indice du registre correspondant.                    * +*                                                                             * +*  Description : Crée un opérande représentant un registre ARMv7.             * +*                                                                             * +*  Retour      : Adresse de la structure mise en place.                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GArchOperand *translate_armv7_register(uint8_t index) +{ +    GArchOperand *result;                   /* Opérande à faire remonter   */ +    GArmV7Register *reg;                    /* Register à représenter      */ + +    reg = g_armv7_register_new(index); + +    if (reg == NULL) +        result = NULL; +    else +        result = g_register_operand_new(G_ARCH_REGISTER(reg)); + +    return result; + +} diff --git a/src/arch/arm/v7/helpers.h b/src/arch/arm/v7/helpers.h new file mode 100644 index 0000000..9ea0d74 --- /dev/null +++ b/src/arch/arm/v7/helpers.h @@ -0,0 +1,40 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * helpers.h - prototypes pour l'aide à la mise en place des opérandes ARMv7 + * + * 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 _ARCH_ARM_V7_HELPERS_H +#define _ARCH_ARM_V7_HELPERS_H + + +#include <stdint.h> + + +#include "../../operand.h" + + + +/* Crée un opérande représentant un registre ARMv7. */ +GArchOperand *translate_armv7_register(uint8_t); + + + +#endif  /* _ARCH_ARM_V7_HELPERS_H */ diff --git a/src/arch/arm/v7/instruction.c b/src/arch/arm/v7/instruction.c index 24135f3..de81056 100644 --- a/src/arch/arm/v7/instruction.c +++ b/src/arch/arm/v7/instruction.c @@ -156,9 +156,9 @@ static void g_armv7_instruction_finalize(GArmV7Instruction *instr)  *                                                                             *  ******************************************************************************/ -GArmV7Instruction *g_armv7_instruction_new(const char *keyword) +GArchInstruction *g_armv7_instruction_new(const char *keyword)  { -    GArmV7Instruction *result;                /* Structure à retourner       */ +    GArchInstruction *result;               /* Structure à retourner       */      result = g_object_new(G_TYPE_ARMV7_INSTRUCTION, NULL); @@ -176,16 +176,18 @@ GArmV7Instruction *g_armv7_instruction_new(const char *keyword)  *                                                                             *  *  Description : Définit si une instruction ARMv7 met à jour les drapeaux.    *  *                                                                             * -*  Retour      : -                                                            * +*  Retour      : Bilan de l'opération.                                        *  *                                                                             *  *  Remarques   : -                                                            *  *                                                                             *  ******************************************************************************/ -void g_armv7_instruction_define_setflags(GArmV7Instruction *instr, bool set) +bool g_armv7_instruction_define_setflags(GArmV7Instruction *instr, bool set)  {      instr->setflags = set; +    return true; +  } diff --git a/src/arch/arm/v7/instruction.h b/src/arch/arm/v7/instruction.h index 97ee31a..291f2c9 100644 --- a/src/arch/arm/v7/instruction.h +++ b/src/arch/arm/v7/instruction.h @@ -30,6 +30,9 @@  #include <stdint.h> +#include "../../instruction.h" + +  #define G_TYPE_ARMV7_INSTRUCTION               g_armv7_instruction_get_type()  #define G_ARMV7_INSTRUCTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_armv7_instruction_get_type(), GArmV7Instruction)) @@ -50,10 +53,10 @@ typedef struct _GArmV7InstructionClass GArmV7InstructionClass;  GType g_armv7_instruction_get_type(void);  /* Crée une instruction pour l'architecture ARMv7. */ -GArmV7Instruction *g_armv7_instruction_new(const char *); +GArchInstruction *g_armv7_instruction_new(const char *);  /* Définit si une instruction ARMv7 met à jour les drapeaux. */ -void g_armv7_instruction_define_setflags(GArmV7Instruction *, bool); +bool g_armv7_instruction_define_setflags(GArmV7Instruction *, bool);  /* Indique si une instruction ARMv7 met à jour les drapeaux. */  bool g_armv7_instruction_get_setflags(const GArmV7Instruction *); diff --git a/src/arch/arm/v7/opcodes/Makefile.am b/src/arch/arm/v7/opcodes/Makefile.am new file mode 100644 index 0000000..e77b7e8 --- /dev/null +++ b/src/arch/arm/v7/opcodes/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libarcharmv7opcodes.la + +libarcharmv7opcodes_la_SOURCES = 		\ +	mov.c								\ +	subs.c + +libarcharmv7opcodes_la_LIBADD = + +libarcharmv7opcodes_la_CFLAGS = $(AM_CFLAGS) + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/src/arch/arm/v7/opdefs/Makefile.am b/src/arch/arm/v7/opdefs/Makefile.am new file mode 100644 index 0000000..8a799b1 --- /dev/null +++ b/src/arch/arm/v7/opdefs/Makefile.am @@ -0,0 +1,37 @@ + +include ../../../../../tools/d2c.mk + + +D2C_BIN = ../../../../../tools/d2c + +D2C_OUTDIR = $(PWD)/.. + +D2C_ARCH = armv7 +D2C_HEADER = _ARCH_ARM_V7 + +D2C_ENCODINGS =							\ +	-e a=								\ +	-e t=thumb_ + +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, " + +ARMV7_DEFS = 							\ +	mov_A88104.d						\ +	subs_B9320.d + + +all: $(ARMV7_DEFS:.d=.g) untabify_disass fix_includes_in_c finish_disass + +fix_includes_in_c: +	find ../opcodes -name '*c' -exec sed -i 's/##INCLUDES##/\n#include "..\/instruction.h"\n#include "..\/..\/instruction.h"\n#include "..\/helpers.h"\n#include "..\/..\/..\/..\/common\/bconst.h"\n\n/' {} \; + +finish_disass: $(D2C_OUTDIR)/opcodes/opcodes.h +	sed -i 's/##INCLUDES##/#include\ <stdint.h>\n\n#include "..\/..\/..\/instruction.h"/' $< +	if ! grep -q 'endif' $<; then echo -en "\n\n#endif  /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ; fi + +clean: +	rm -f $(ARMV7_DEFS:.d=.g) $(D2C_OUTDIR)/opcodes/*c $(D2C_OUTDIR)/opcodes/opcodes.h diff --git a/src/arch/arm/v7/opdefs/mov_A88104.d b/src/arch/arm/v7/opdefs/mov_A88104.d new file mode 100644 index 0000000..1efebd3 --- /dev/null +++ b/src/arch/arm/v7/opdefs/mov_A88104.d @@ -0,0 +1,47 @@ + +/* 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 MOV (register, ARM) + +@encoding(A1) { + +    @word cond(4) 0 0 0 1 1 0 1 S(1) 0 0 0 0 Rd(4) 0 0 0 0 0 0 0 0 Rm(4) + +    @syntax {S} {c} <Rd> <Rm> + +    @conv { + +        S = SetFlags(S) +        c = Condition(cond) +        Rd = Register(Rd) +        Rm = Register(Rm) + +    } + +    @rules { + +        if ((Rd == '1111') && (S == '1')) ; see SUBS PC, LR and related instructions (ARM) + +    } + +} diff --git a/src/arch/arm/v7/opdefs/subs_B9320.d b/src/arch/arm/v7/opdefs/subs_B9320.d new file mode 100644 index 0000000..335e614 --- /dev/null +++ b/src/arch/arm/v7/opdefs/subs_B9320.d @@ -0,0 +1,44 @@ + +/* 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 SUBS PC, LR and related instructions (ARM) + +@encoding(A1) { + +    @word cond(4) 0 0 1 opcode(4) 1 Rn(4) 1 1 1 1 imm12(12) + +    @syntax {c} <Rn> <#const> + +    @conv { + +        c = Condition(cond) +        Rn = Register(Rn) +        const = ExpandImmC32(imm12) + +    } + +    @rules { + +    } + +} diff --git a/src/arch/arm/v7/processor.c b/src/arch/arm/v7/processor.c index 3ce1623..dd2f39f 100644 --- a/src/arch/arm/v7/processor.c +++ b/src/arch/arm/v7/processor.c @@ -218,7 +218,7 @@ static GArchInstruction *g_armv7_processor_disassemble(const GArmV7Processor *pr      //exit(1); -    raw = 0xe1a0000a; +      start = get_phy_addr(pos); @@ -226,16 +226,24 @@ static GArchInstruction *g_armv7_processor_disassemble(const GArmV7Processor *pr      if (!read_u32(&raw, data, &start, end, G_ARCH_PROCESSOR(proc)->endianness))          return NULL; +    if (raw == 0xe1a0000a) +    printf("process @ 0x%x :: 0x%08x\n", start, raw); +    /*      if (raw == 0xe1a0000a)          printf("read !!!!!!!\n"); - +    */      /* TODO : thumb... */      result = process_armv7_instruction_set_encoding(raw); +    if (raw == 0xe1a0000a) +        printf(" --> %p\n", result); + + +      if (result != NULL)          advance_vmpa(pos, 4); diff --git a/src/arch/register-int.h b/src/arch/register-int.h index fe9db8c..bf2ad75 100644 --- a/src/arch/register-int.h +++ b/src/arch/register-int.h @@ -28,6 +28,12 @@  #include "register.h" +#include "operand-int.h" + + + +/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */ +  /* Produit une empreinte à partir d'un registre. */  typedef guint (* reg_hash_fc) (const GArchRegister *); @@ -69,4 +75,27 @@ struct _GArchRegisterClass +/* ------------------------- REGISTRE SOUS FORME D'OPERANDE ------------------------- */ + + +/* Définition d'un opérande visant un registre (instance) */ +struct _GRegisterOperand +{ +    GArchOperand parent;                    /* Instance parente            */ + +    GArchRegister *reg;                     /* Registre représenté         */ +    bool is_written;                        /* Changement de contenu       */ + +}; + + +/* Définition d'un opérande visant un registre (classe) */ +struct _GRegisterOperandClass +{ +    GArchOperandClass parent;               /* Classe parente              */ + +}; + + +  #endif  /* _ARCH_REGISTER_INT_H */ diff --git a/src/arch/register.c b/src/arch/register.c index 389e71a..706fcd4 100644 --- a/src/arch/register.c +++ b/src/arch/register.c @@ -28,6 +28,9 @@ +/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */ + +  /* Initialise la classe des registres. */  static void g_arch_register_class_init(GArchRegisterClass *); @@ -36,6 +39,28 @@ static void g_arch_register_init(GArchRegister *); +/* ------------------------- REGISTRE SOUS FORME D'OPERANDE ------------------------- */ + + +/* Initialise la classe des opérandes de registre. */ +static void g_register_operand_class_init(GRegisterOperandClass *); + +/* Initialise une instance d'opérande de registre. */ +static void g_register_operand_init(GRegisterOperand *); + +/* Compare un opérande avec un autre. */ +static bool g_register_operand_compare(const GRegisterOperand *, const GRegisterOperand *); + +/* Traduit un opérande en version humainement lisible. */ +static void g_register_operand_print(const GRegisterOperand *, GBufferLine *, AsmSyntax); + + + +/* ---------------------------------------------------------------------------------- */ +/*                              PUR REGISTRE DU MATERIEL                              */ +/* ---------------------------------------------------------------------------------- */ + +  /* Indique le type défini pour une représentation d'un registre. */  G_DEFINE_TYPE(GArchRegister, g_arch_register, G_TYPE_OBJECT); @@ -210,3 +235,180 @@ bool g_arch_register_is_stack_pointer(const GArchRegister *reg)      return result;  } + + + +/* ---------------------------------------------------------------------------------- */ +/*                           REGISTRE SOUS FORME D'OPERANDE                           */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini par la GLib pour un opérande de registre Dalvik. */ +G_DEFINE_TYPE(GRegisterOperand, g_register_operand, G_TYPE_ARCH_OPERAND); + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : klass = classe à initialiser.                                * +*                                                                             * +*  Description : Initialise la classe des opérandes de registre Dalvik.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_class_init(GRegisterOperandClass *klass) +{ + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = instance à initialiser.                            * +*                                                                             * +*  Description : Initialise une instance d'opérande de registre Dalvik.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_init(GRegisterOperand *operand) +{ +    GArchOperand *parent;                   /* Instance parente            */ + +    parent = G_ARCH_OPERAND(operand); + +    parent->compare = (operand_compare_fc)g_register_operand_compare; +    parent->print = (operand_print_fc)g_register_operand_print; + +    operand->is_written = false; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : reg = registre déjà en place.                                * +*                                                                             * +*  Description : Crée un opérande visant un registre.                         * +*                                                                             * +*  Retour      : Opérande mis en place.                                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GArchOperand *g_register_operand_new(GArchRegister *reg) +{ +    GRegisterOperand *result;         /* Structure à retourner       */ + +    result = g_object_new(G_TYPE_REGISTER_OPERAND, NULL); + +    result->reg = reg; + +    return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande représentant un registre.                 * +*                                                                             * +*  Description : Fournit le registre Dalvik associé à l'opérande.             * +*                                                                             * +*  Retour      : Représentation interne du registre.                          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +GArchRegister *g_register_operand_get_register(const GRegisterOperand *operand) +{ +    return operand->reg; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : a = premier opérande à consulter.                            * +*                b = second opérande à consulter.                             * +*                                                                             * +*  Description : Compare un opérande avec un autre.                           * +*                                                                             * +*  Retour      : Bilan de la comparaison.                                     * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool g_register_operand_compare(const GRegisterOperand *a, const GRegisterOperand *b) +{ +    return (g_arch_register_compare(a->reg, b->reg) == 0); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande à traiter.                                * +*                line    = ligne tampon où imprimer l'opérande donné.         * +*                syntax  = type de représentation demandée.                   * +*                                                                             * +*  Description : Traduit un opérande en version humainement lisible.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void g_register_operand_print(const GRegisterOperand *operand, GBufferLine *line, AsmSyntax syntax) +{ +    g_arch_register_print(operand->reg, line, syntax); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande représentant un registre à mettre à jour. * +*                                                                             * +*  Description : Marque l'opérande comme étant écrit plutôt que consulté.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_register_operand_mark_as_written(GRegisterOperand *operand) +{ +    operand->is_written = true; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : operand = opérande représentant un registre à consulter.     * +*                                                                             * +*  Description : Indique le type d'accès réalisé sur l'opérande.              * +*                                                                             * +*  Retour      : Type d'accès : true en cas d'écriture, false sinon.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool g_register_operand_is_written(const GRegisterOperand *operand) +{ +    return operand->is_written; + +} diff --git a/src/arch/register.h b/src/arch/register.h index 4e9d447..f5841f7 100644 --- a/src/arch/register.h +++ b/src/arch/register.h @@ -30,10 +30,14 @@  #include "archbase.h" +#include "operand.h"  #include "../glibext/gbufferline.h" +/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */ + +  #define G_TYPE_ARCH_REGISTER               g_arch_register_get_type()  #define G_ARCH_REGISTER(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_register_get_type(), GArchRegister))  #define G_IS_ARCH_REGISTER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_register_get_type())) @@ -72,4 +76,39 @@ bool g_arch_register_is_stack_pointer(const GArchRegister *); +/* ------------------------- REGISTRE SOUS FORME D'OPERANDE ------------------------- */ + + +#define G_TYPE_REGISTER_OPERAND                  g_register_operand_get_type() +#define G_REGISTER_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_register_operand_get_type(), GRegisterOperand)) +#define G_IS_REGISTER_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_register_operand_get_type())) +#define G_REGISTER_OPERAND_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_REGISTER_OPERAND, GRegisterOperandClass)) +#define G_IS_REGISTER_OPERAND_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_REGISTER_OPERAND)) +#define G_REGISTER_OPERAND_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_REGISTER_OPERAND, GRegisterOperandClass)) + + +/* Définition d'un opérande visant un registre (instance) */ +typedef struct _GRegisterOperand GRegisterOperand; + +/* Définition d'un opérande visant un registre (classe) */ +typedef struct _GRegisterOperandClass GRegisterOperandClass; + + +/* Indique le type défini par la GLib pour un opérande de registre. */ +GType g_register_operand_get_type(void); + +/* Crée un opérande visant un registre. */ +GArchOperand *g_register_operand_new(GArchRegister *); + +/* Fournit le registre associé à l'opérande. */ +GArchRegister *g_register_operand_get_register(const GRegisterOperand *); + +/* Marque l'opérande comme étant écrit plutôt que consulté. */ +void g_register_operand_mark_as_written(GRegisterOperand *); + +/* Indique le type d'accès réalisé sur l'opérande. */ +bool g_register_operand_is_written(const GRegisterOperand *); + + +  #endif  /* _ARCH_ARCH_REGISTER_H */ diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..9a91f9d --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,25 @@ + +BUILT_SOURCES = d2c-d2c_gram.h + +AM_YFLAGS = -d + +bin_PROGRAMS = d2c + + +d2c_SOURCES =							\ +	coder.h coder.c						\ +	d2c_gram.y							\ +	d2c_tok.l + +d2c_YFLAGS = -d -p d2c_ -o y.tab.c + +d2c_LFLAGS = -P d2c_ -o lex.yy.c + + +AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) + +AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) + + +# Automake fait les choses à moitié +CLEANFILES = d2c_gram.h d2c_gram.c d2c-d2c_tok.c diff --git a/tools/coder.c b/tools/coder.c new file mode 100644 index 0000000..3606bea --- /dev/null +++ b/tools/coder.c @@ -0,0 +1,1878 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * coder.c - lecture automatisée des spécifications d'architecture + * + * 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 "coder.h" + + +#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> + + + +/* -------------------------- 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      */ + +} string_exch; + + +struct _encoding_spec; + + +/* Suivi des constructions */ +struct _rented_coder +{ +    const char *outdir;                     /* Lieu d'enregistrement       */ +    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   */ + +    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   */ +    size_t specs_count;                     /* Nombre de ces définitions   */ +    struct _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 *); + + + +/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ + + +/* Elément d'un mot décodé */ +typedef struct _dec_bitfield +{ +    char *name;                             /* Désignation humaine         */ +    unsigned int start;                     /* Position de départ          */ +    unsigned int length;                    /* Taille du champ             */ + +} 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 *); + + + +/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ + + +/* Fonction de conversion */ +typedef struct _conv_func +{ +    char *dest;                             /* Variable de destination     */ +    char *func;                             /* Fonction de conversion      */ +    char *arg;                              /* Argument de cette fonction  */ + +} 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 --------------------------- */ + + +/* Ouvre un fichier en écriture pour y placer du code. */ +static int create_code_file(const rented_coder *, const char *, const char *, const char *, char, bool *); + +/* 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); + + + +/* ---------------------------------------------------------------------------------- */ +/*                            CONSTRUCTION SELON COMMANDES                            */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Débute la définition d'une fonction de désassemblage.        * +*                                                                             * +*  Retour      : Gestionnaire mis en place.                                   * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +rented_coder *create_coder(void) +{ +    rented_coder *result;                   /* Structure à renvoyer        */ + +    result = (rented_coder *)calloc(1, sizeof(rented_coder)); + +    result->cur_spec = (encoding_spec *)calloc(1, sizeof(encoding_spec)); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder = gestion par la machine en remplacement de l'humain.  * +*                                                                             * +*  Description : Supprime le codeur de la mémoire.                            * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +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); + +    if (coder->ins != NULL) +        free(coder->ins); + +    if (coder->details != NULL) +        free(coder->details); + +    for (i = 0; i < coder->specs_count; i++) +        free_encoding_spec(&coder->specs[i]); + +    if (coder->specs != NULL) +        free(coder->specs); + +    free_encoding_spec(coder->cur_spec); + +    free(coder->cur_spec); + +    free(coder); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder = gestion par la machine en remplacement de l'humain.  * +*                                                                             * +*  Description : Détermine si les propriétés de base d'un codeur sont là.     * +*                                                                             * +*  Retour      : Bilan de l'état opérationnel.                                * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool do_basic_checks_with_coder(const rented_coder *coder) +{ +    return (coder->outdir != NULL && coder->arch != NULL && coder->header != NULL); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. * +*                outdir = répertoire de génération des fichiers.              * +*                                                                             * +*  Description : Spécifie le répertoire de base pour les sorties de code.     * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void set_coder_output_directory(rented_coder *coder, const char *outdir) +{ +    coder->outdir = outdir; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder = gestion par la machine en remplacement de l'humain.  * +*                arch  = désignation pour le code de l'architecture lue.      * +*                                                                             * +*  Description : Détermine l'architecture visée par les traitements.          * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void set_coder_arch(rented_coder *coder, const char *arch) +{ +    coder->arch = arch; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. * +*                header = base des définitions de protection d'en-têtes.      * +*                                                                             * +*  Description : Définit la base des protections des fichiers d'en-tête.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void set_coder_header_base(rented_coder *coder, const char *header) +{ +    coder->header = 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.         * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void register_encoding_in_coder(rented_coder *coder, const char *src, const char *dest) +{ +    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; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder   = gestion par la machine en remplacement de l'humain.* +*                copy    = droits de copie en anglais.                        * +*                ins     = désignation humaine de l'instruction.              * +*                details = compléments d'informations éventuels ou NULL.      * +*                                                                             * +*  Description : Enregistre les contours d'une instruction d'assemblage.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, const char *details) +{ +    coder->copyright = copy; +    coder->ins = make_string_lower(ins); +    coder->details = (details != NULL ? make_callable(details, true) : strdup("")); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                             REPRESENTATION D'ENCODAGES                             */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  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.                 * +*                                                                             * +*  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 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.                * +*                                                                             * +*  Description : Ajoute une règle complète à la définition d'un codage.       * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void add_conditional_rule_to_coder(rented_coder *coder, cond_expr *expr, CondActionType action, const char *details) +{ +    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)); + +    rule = &spec->rules[spec->rules_count - 1]; + +    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; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                             GENERATIONS DE CODE SOURCE                             */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. * +*                dir    = répertoire final de destination.                    * +*                prefix = type d'encodage à répercuter sur le nom de fichier. * +*                name   = nom brut du fichier à ouvrir.                       * +*                ext    = extension à donner au fichier à ouvrir.             * +*                exist  = indique si le fichier était présent avant. [OUT]    * +*                                                                             * +*  Description : Ouvre un fichier en écriture pour y placer du code.          * +*                                                                             * +*  Retour      : Descripteur du fichier ouvert ou -1 en cas d'échec.          * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static int create_code_file(const rented_coder *coder, const char *dir, const char *prefix, const char *name, char ext, bool *exist) +{ +    int result;                         /* Descripteur à retourner     */ +    size_t length;                      /* Taille du nom de fichier    */ +    char *pathname;                     /* Chemin d'accès à constituer */ + +    length = strlen(coder->outdir) + 1 + strlen(dir) + 1 + strlen(prefix) + strlen(name) + 3; +    pathname = (char *)calloc(length, sizeof(char)); +    snprintf(pathname, length, "%s/%s/%s%s.%c", coder->outdir, dir, prefix, name, ext); + +    *exist = (access(pathname, W_OK) == 0); + +    result = open(pathname, O_WRONLY | O_CREAT | O_APPEND, 0644); +    if (result == -1) perror("open()"); + +    free(pathname); + +    if (!*exist && result != -1) +    { +        dprintf(result, "\n"); + +        dprintf(result, "/* Chrysalide - Outil d'analyse de fichiers binaires\n"); +        dprintf(result, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext); +        dprintf(result, " *\n"); +        dprintf(result, " * %s\n", coder->copyright); +        dprintf(result, " *\n"); +        dprintf(result, " *  This file is part of Chrysalide.\n"); +        dprintf(result, " *\n"); +        dprintf(result, " *  Chrysalide is free software; you can redistribute it and/or modify\n"); +        dprintf(result, " *  it under the terms of the GNU General Public License as published by\n"); +        dprintf(result, " *  the Free Software Foundation; either version 3 of the License, or\n"); +        dprintf(result, " *  (at your option) any later version.\n"); +        dprintf(result, " *\n"); +        dprintf(result, " *  Chrysalide is distributed in the hope that it will be useful,\n"); +        dprintf(result, " *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); +        dprintf(result, " *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"); +        dprintf(result, " *  GNU General Public License for more details.\n"); +        dprintf(result, " *\n"); +        dprintf(result, " *  You should have received a copy of the GNU General Public License\n"); +        dprintf(result, " *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.\n"); +        dprintf(result, " */\n"); + +        dprintf(result, "\n"); +        dprintf(result, "\n"); + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder   = gestion par la machine en remplacement de l'humain.* +*                                                                             * +*  Description : Débute la définition des fonctions issues des spécifications.* +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +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é        */ +    bool exist;                             /* Présence du fichier visé ?  */ +    int header_fd;                          /* Fichier de déclarations     */ +    char *dash;                             /* Présence d'un tiret ?       */ +    char *filename;                         /* Nom de fichier commun       */ +    int code_fd;                            /* Fichier de définitions      */ + +    result = true; + +    for (i = 0; i < coder->encodings_count && result; i++) +    { +        encoding = &coder->encodings[i]; + +        /* Fichier de déclarations */ + +        header_fd = create_code_file(coder, "opcodes", encoding->dest, "opcodes", 'h', &exist); +        if (header_fd == -1) return false; + +        if (!exist) +        { +            dprintf(header_fd, "#ifndef %s_OPCODES_OPCODES_H\n", coder->header); +            dprintf(header_fd, "#define %s_OPCODES_OPCODES_H\n", coder->header); + +            dprintf(header_fd, "\n"); +            dprintf(header_fd, "\n"); +            dprintf(header_fd, "##INCLUDES##\n"); +            dprintf(header_fd, "\n"); +            dprintf(header_fd, "\n"); +            dprintf(header_fd, "\n"); + +        } + +        /* Fichier de définitions */ + +        dash = strchr(coder->ins, '-'); + +        if (dash == NULL) +            code_fd = create_code_file(coder, "opcodes", encoding->dest, coder->ins, 'c', &exist); + +        else +        { +            filename = strdup(coder->ins); + +            dash = strchr(filename, '-'); +            *dash = '\0'; + +            code_fd = create_code_file(coder, "opcodes", encoding->dest, filename, 'c', &exist); + +            free(filename); + +        } + +        if (!exist) +        { +            dprintf(code_fd, "#include \"opcodes.h\"\n"); +            dprintf(code_fd, "\n"); +            dprintf(code_fd, "##INCLUDES##\n"); + +        } + +        if (code_fd == -1) +        { +            close(header_fd); +            return false; +        } + +        /* Production de code... */ + +        result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd); + +        close(header_fd); +        close(code_fd); + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder    = gestion par la machine en remplacement d'humain.  * +*                encoding = sélection de l'encodage à traiter.                * +*                hfd      = flux ouvert en écriture pour les déclarations.    * +*                cfd      = flux ouvert en écriture pour les définitions.     * +*                                                                             * +*  Description : Ecrit une partie des fonctions issues des spécifications.    * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd) +{ +    bool result;                            /* Bilan à retourner           */ +    char *keyword;                          /* Mot clef appelable en code  */ +    unsigned int wide;                      /* Taille des mots             */ +    size_t i;                               /* Boucle de parcours          */ +    encoding_spec *spec;                    /* Définition à traiter        */ +    size_t maxlen;                          /* Taille à compléter          */ + +    result = true; + +    keyword = make_callable(coder->ins, false); + +    /* Recherche de la taille des mots */ + +    wide = -1; + +    for (i = 0; i < coder->specs_count; i++) +    { +        spec = &coder->specs[i]; + +        if (strcmp(encoding->src, spec->prefix) != 0) +            continue; + +        wide = spec->curpos; +        break; + +    } + +    /* Rien n'a été trouvé à faire... */ +    if (wide == -1) goto damsic_exit; + +    /* Désassemblage : déclaration */ + +    dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins); +    dprintf(hfd, "GArchInstruction *%s_read_instr_%s%s(uint%u_t);\n", coder->arch, keyword, coder->details, wide); +    dprintf(hfd, "\n"); + +    /* Désassemblage : définitions */ + +    dprintf(cfd, "\n"); + +    dprintf(cfd, "/******************************************************************************\n"); +    dprintf(cfd, "*                                                                             *\n"); +    dprintf(cfd, "*  Paramètres  : raw = données brutes à analyser.                             *\n"); +    dprintf(cfd, "*                                                                             *\n"); +    dprintf(cfd, "*  Description : Décode une instruction de type '%s'.", coder->ins); + +    maxlen = 28 - strlen(coder->ins); + +    if (maxlen < 28) +        dprintf(cfd, "%*s\n", (int)maxlen, "*"); +    else +        dprintf(cfd, "*\n"); + +    dprintf(cfd, "                                                                              *\n"); +    dprintf(cfd, "*  Retour      : Bilan de l'opération.                                        *\n"); +    dprintf(cfd, "*                                                                             *\n"); +    dprintf(cfd, "*  Remarques   : -                                                            *\n"); +    dprintf(cfd, "*                                                                             *\n"); +    dprintf(cfd, "******************************************************************************/\n"); + +    dprintf(cfd, "\n"); + +    dprintf(cfd, "GArchInstruction *%s_read_instr_%s%s(uint%u_t raw)", coder->arch, keyword, coder->details, wide); +    dprintf(cfd, "\n"); +    dprintf(cfd, "{"); +    dprintf(cfd, "\n"); + +    dprintf(cfd, "\tGArchInstruction *result;               /* Instruction créée à renvoyer*/\n"); + +    dprintf(cfd, "\n"); +    dprintf(cfd, "\tresult = NULL;\n"); +    dprintf(cfd, "\n"); + +    for (i = 0; i < coder->specs_count && result; i++) +    { +        spec = &coder->specs[i]; + +        if (strcmp(encoding->src, spec->prefix) != 0) +            continue; + +        result = write_coder_spec_disass(coder, cfd, spec, keyword, wide); + +    } + +    dprintf(cfd, "\treturn result;\n"); +    dprintf(cfd, "\n"); + +    dprintf(cfd, "}\n"); +    dprintf(cfd, "\n"); + + damsic_exit: + +    free(keyword); + +    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 new file mode 100644 index 0000000..c96f787 --- /dev/null +++ b/tools/coder.h @@ -0,0 +1,158 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * coder.h - prototypes pour la lecture automatisée des spécifications d'architecture + * + * 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 _ARCH_ARM_V7_OPDEFS_CODER_H +#define _ARCH_ARM_V7_OPDEFS_CODER_H + + +#include <stdbool.h> + + + +/* Suivi des constructions */ +typedef struct _rented_coder rented_coder; + + + +/* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */ + + +/* Débute la définition d'une fonction de désassemblage. */ +rented_coder *create_coder(void); + +/* Supprime le codeur de la mémoire. */ +void delete_coder(rented_coder *); + +/* Détermine si les propriétés de base d'un codeur sont là. */ +bool do_basic_checks_with_coder(const rented_coder *); + +/* Spécifie le répertoire de base pour les sorties de code. */ +void set_coder_output_directory(rented_coder *, const char *); + +/* Détermine l'architecture visée par les traitements. */ +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 *); + +/* Enregistre les contours d'une instruction d'assemblage. */ +void save_notes_for_coder(rented_coder *, char *, char *, const char *); + + + +/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */ + + + +/* Enregistre une définition supplémentaire. */ +void push_encoding_spec(rented_coder *, char *, unsigned int); + + + +/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */ + + +/* Note la présence d'un champ remarquable dans une définition. */ +void register_named_field_in_coder(rented_coder *, char *, unsigned int); + +/* Note la présence d'un bit invariable dans une définition. */ +void register_bit_in_coder(rented_coder *, int); + +/* Indique le nombre de bits traités. */ +unsigned int count_coder_bits(const rented_coder *); + + + +/* ---------------------------- SYNTAXE DES INSTRUCTIONS ---------------------------- */ + + +/* Enregistre la présence d'un nouvel opérande. */ +void register_syntax_item_in_coder(rented_coder *, char *, bool); + + + +/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */ + + +/* Enregistre la function de conversion du brut à l'utile. */ +void register_conversion_in_coder(rented_coder *, char *, char *, char *); + + + +/* --------------------------- 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 *); + + + +/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */ + + +/* Débute la définition des fonctions issues des spécifications. */ +bool dump_all_routines_using_coder(const rented_coder *); + + + +#endif  /* _ARCH_ARM_V7_OPDEFS_CODER_H */ diff --git a/tools/d2c.mk b/tools/d2c.mk new file mode 100644 index 0000000..78cc374 --- /dev/null +++ b/tools/d2c.mk @@ -0,0 +1,22 @@ + +.NOTPARALLEL: + +d2c_verbose = $(d2c_verbose_@AM_V@) +d2c_verbose_ = $(d2c_verbose_@AM_DEFAULT_V@) +d2c_verbose_0 = @echo "  D2C     " $<; + +# D2C_BIN =  +# D2C_OUTDIR =  +# D2C_ARCH =  +# D2C_HEADER =  +# D2C_ENCODINGS =  +# D2C_MACROS =  + +SUFFIXES = .g + +.d.g: +	$(d2c_verbose)$(D2C_BIN) -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) < $< +	@touch $@ + +untabify_disass: +	find $(D2C_OUTDIR)/opcodes -name '*c' -exec sed -i 's/\t/    /g' {} \; diff --git a/tools/d2c_gram.y b/tools/d2c_gram.y new file mode 100644 index 0000000..6fc8fb7 --- /dev/null +++ b/tools/d2c_gram.y @@ -0,0 +1,329 @@ + +%{ + +#include <getopt.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#include "coder.h" + + +extern int yylex(); + +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); + +/* Affiche des indications sur l'utilisation du programme. */ +static void show_usage(const char *argv0); + + +%} + + +%code requires { + +/* Pour la définition des expressions conditionnelles... */ +#include "coder.h" + +struct action_tmp +{ +    CondActionType action; +    const char *details; +}; + +} + +%union { + +    char *string;                           /* Chaîne de caractères #1     */ +    const char *cstring;                    /* Chaîne de caractères #2     */ + + +    int integer; + + +    cond_expr *expr;                        /* Expression de déclenchement */ +    struct action_tmp tmpa;                 /* Transfert temporaire        */ + +} + +%parse-param { rented_coder *coder } + + +%token COPYRIGHT +%token TITLE +%token INS_NAME INS_DETAILS + +%token ENCODING +%token THUMB ARCH NUMBER +%token ENC_START ENC_END + +%token WORD HALF NAME SIZE BIT + +%token SYNTAX OPERAND_INTERNAL OPERAND_VISIBLE + +%token CONV EQ ARG + +%token RULES IF EXPR_START EQUAL BINVAL EXPR_END AND THEN SEE + + +%type <string> COPYRIGHT INS_NAME +%type <cstring> INS_DETAILS + +%type <integer> NUMBER + +%type <string> NAME +%type <integer> SIZE BIT + +%type <string> OPERAND_INTERNAL OPERAND_VISIBLE + +%type <string> ARG + +%type <expr> rule_cond +%type <string> BINVAL +%type <tmpa> action + + +%% + + +input : name encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; } + +name : COPYRIGHT TITLE INS_NAME             { save_notes_for_coder(coder, $1, $3, NULL); } +     | COPYRIGHT TITLE INS_NAME INS_DETAILS { save_notes_for_coder(coder, $1, $3, $4); } + + + + +encodings : /* empty */ +          | encoding encodings + +encoding : ENCODING THUMB NUMBER content { push_encoding_spec(coder, strdup("t"), $3); } +         | ENCODING ARCH NUMBER content  { push_encoding_spec(coder, strdup("a"), $3); } + + +content : /* empty */ +        | bitfield content +        | syntax content +        | conversions content +        | rules content + + +bitfield : HALF bits { if (count_coder_bits(coder) != 16) YYABORT; } +         | WORD bits { if (count_coder_bits(coder) != 32) YYABORT; } + +bits : /* empty */ +     | NAME SIZE bits   { register_named_field_in_coder(coder, $1, $2); } +     | BIT bits         { register_bit_in_coder(coder, $1); } + + +syntax : SYNTAX operands + +operands : /* empty */ +         | operands OPERAND_INTERNAL { register_syntax_item_in_coder(coder, $2, true); } +         | operands OPERAND_VISIBLE  { register_syntax_item_in_coder(coder, $2, false); } + + +conversions : CONV substitutions + +substitutions : /* empty */ +              | substitutions NAME EQ NAME ARG { register_conversion_in_coder(coder, $2, $4, $5); } + + +rules : RULES rules_list + +rules_list : /* empty */ +           | rules_list rule + +rule : IF EXPR_START rule_cond EXPR_END THEN action +                                { add_conditional_rule_to_coder(coder, $3, $6.action, $6.details); } + +rule_cond : NAME EQUAL BINVAL   { $$ = build_simple_cond_expression($1, CCT_EQUAL, $3); } +          | EXPR_START rule_cond EXPR_END AND EXPR_START rule_cond EXPR_END +                                { $$ = build_composed_cond_expression($2, COT_AND, $6); } + +action : SEE INS_DETAILS { $$.action = CAT_SEE; $$.details = $2; } + + +%% + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : coder = codeur impliqué dans le processus.                   * +*                msg   = message d'erreur.                                    * +*                                                                             * +*  Description : Affiche un message d'erreur suite à l'analyse en échec.      * +*                                                                             * +*  Retour      : 0                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static int d2c_error(rented_coder *coder, char *msg) +{ +	printf("yyerror : %s\n", msg); + +	return 0; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : argv0 = nombre du programme exécuté.                         * +*                                                                             * +*  Description : Affiche des indications sur l'utilisation du programme.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void show_usage(const char *argv0) +{ +    printf("\n"); + +    printf("Usage: %s [options] < file\n", argv0); + +    printf("\n"); + +    printf("Options:\n"); + +    printf("\n"); + +    printf("\t-h | --help\t\t\tDisplay this messsage.\n"); +    printf("\t-d | --dir <string>\t\tSpecify the main output directory.\n"); +    printf("\t-a | --arch <string>\t\tDefine the archicture to handle.\n"); +    printf("\t-H | --header <string>\t\tSet the base of the #ifndef / #define game.\n"); +    printf("\t-e | --encoding <string>\tDefine encoding prefixes for files.\n"); +    printf("\t-m | --macro <string>\t\tRegister some conversion functions.\n"); + +    printf("\n"); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : argc = nombre d'arguments dans la ligne de commande.         * +*                argv = arguments de la ligne de commande.                    * +*                                                                             * +*  Description : Point d'entrée du programme.                                 * +*                                                                             * +*  Retour      : EXIT_SUCCESS si le prgm s'est déroulé sans encombres.        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +int main(int argc, char **argv) +{ +    int result;                             /* Bilan à retourner           */ +    rented_coder *coder;                    /* Codeur à briffer & employer */            +    int index;                              /* Indice de fichier à traiter */ +    bool need_help;                         /* Affichage de l'aide ?       */ +    bool has_error;                         /* Erreur dans la ligne de cmd.*/ +    int ret;                                /* Bilan d'une lecture d'arg.  */ +    char *sep;                              /* Caratère '=' en coupure     */ + +    static struct option long_options[] = { + +        { "help",       no_argument,        NULL,   'h' }, +        { "dir",        required_argument,  NULL,   'd' }, +        { "arch",       required_argument,  NULL,   'a' }, +        { "header",     required_argument,  NULL,   'H' }, +        { "encoding",   required_argument,  NULL,   'e' }, +        { "macro",      required_argument,  NULL,   'M' }, +        { NULL,         0,                  NULL,   0   } + +    }; + +    result = EXIT_SUCCESS; + +    coder = create_coder(); + +    index = 0; + +    need_help = false; +    has_error = false; + +    while (!has_error) +    { +        ret = getopt_long(argc, argv, "hd:a:H:e:M:", long_options, &index); +        if (ret == -1) break; + +        switch (ret) +        { +            case 'h': +                need_help = true; +                break; + +            case 'd': +                set_coder_output_directory(coder, optarg); +                break; + +            case 'a': +                set_coder_arch(coder, optarg); +                break; + +            case 'H': +                set_coder_header_base(coder, optarg); +                break; + +            case 'e': + +                sep = strchr(optarg, '='); +                has_error = (sep == NULL); + +                if (!has_error) +                { +                    *sep = '\0'; +                    register_encoding_in_coder(coder, optarg, sep + 1); +                } + +                break; + +            case 'M': + +                sep = strchr(optarg, '='); +                has_error = (sep == NULL); + +                if (!has_error) +                { +                    *sep = '\0'; +                    define_macro_for_coder(coder, optarg, sep + 1); +                } + +                break; + +        } + +    } + +    if (need_help || has_error || !do_basic_checks_with_coder(coder) || optind != argc) +    { +        show_usage(argv[0]); +        result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE); +        goto exit; +    } + +	result = yyparse(coder); + + exit: + +    free_flex_memory(); + +    delete_coder(coder); + +    return result; + +} diff --git a/tools/d2c_tok.l b/tools/d2c_tok.l new file mode 100644 index 0000000..ae4faa3 --- /dev/null +++ b/tools/d2c_tok.l @@ -0,0 +1,165 @@ + +%{ + +typedef struct _rented_coder rented_coder; + + +#include "d2c-d2c_gram.h" + +#include <ctype.h> +#include <string.h> + + +/* Tente de libérer autant de mémoire que possible...  */ +void free_flex_memory(void) ; + + +%} + +%option noyywrap +%option nounput +%option noinput + + +%x comments + +%x ins_name try_details ins_details +%x encoding encoding_type encoding_content + +%x encoding_bits encoding_bits_size + +%x syntax syntax_int syntax_ext + +%x conv_begin conv_content conv_arg + +%x rules_begin rules_content rules_cond rules_cond_binval rules_action rules_actin_see + + +%% + + +[ \t\n]+                            { } + +"/*"                                { BEGIN(comments); } +<comments>"*/"                      { BEGIN(INITIAL); } +<comments>[^*\n]                    { } +<comments>"Copyright"[^\n]*         { d2c_lval.string = strdup(yytext); return COPYRIGHT; } +<comments>"*"                       { } +<comments>"\n"                      { } + + +"@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>[\n]                   { BEGIN(INITIAL); } + +<ins_details>[^\n]*                 { d2c_lval.cstring = yytext; return INS_DETAILS; } +<ins_details>[\n]                   { BEGIN(INITIAL); } + + + +"@encoding"                         { BEGIN(encoding); return ENCODING; } + +<encoding>[ ]                       { } +<encoding>"("                       { BEGIN(encoding_type); } + +<encoding_type>"T"                  { return THUMB; } +<encoding_type>"A"                  { return ARCH; } +<encoding_type>[0-9]                { d2c_lval.integer = atoi(yytext); return NUMBER; } +<encoding_type>")"                  { BEGIN(encoding); } + +<encoding>"{"                       { BEGIN(encoding_content); } +<encoding_content>[ \t\n]+          { } +<encoding_content>"}"               { BEGIN(INITIAL); } + + + +<encoding_content>"@half"           { BEGIN(encoding_bits); return HALF; } +<encoding_content>"@word"           { BEGIN(encoding_bits); return WORD; } + +<encoding_bits>" "                  { } +<encoding_bits>"\n"                 { BEGIN(encoding_content); } +<encoding_bits>[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } + +<encoding_bits>"("                  { BEGIN(encoding_bits_size); } +<encoding_bits_size>[0-9]+          { d2c_lval.integer = atoi(yytext); return SIZE; } +<encoding_bits_size>")"             { BEGIN(encoding_bits); } + +<encoding_bits>[01]                 { d2c_lval.integer = atoi(yytext); return BIT; } + + + +<encoding_content>"@syntax"         { BEGIN(syntax); return SYNTAX; } + +<syntax>[ ]+                        { } +<syntax>"\n"                        { BEGIN(encoding_content); } + +<syntax>"{"                         { BEGIN(syntax_int); } +<syntax_int>[^ \n}]+                { d2c_lval.string = strdup(yytext); return OPERAND_INTERNAL; } +<syntax_int>"}"                     { BEGIN(syntax); } + +<syntax>"<"                         { BEGIN(syntax_ext); } +<syntax_ext>[^ \n>]+                { d2c_lval.string = strdup(yytext); return OPERAND_VISIBLE; } +<syntax_ext>">"                     { BEGIN(syntax); } + + + +<encoding_content>"@conv"           { BEGIN(conv_begin); return CONV; } +<conv_begin>[ ]+                    { } +<conv_begin>"{"                     { BEGIN(conv_content); } +<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>"="                   { 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); } + + + +<encoding_content>"@rules"          { BEGIN(rules_begin); return RULES; } +<rules_begin>[ ]+                   { } +<rules_begin>"{"                    { BEGIN(rules_content); } +<rules_content>[ \t\n]+             { } +<rules_content>"}"                  { BEGIN(encoding_content); } + +<rules_content>"if"                 { BEGIN(rules_cond); return IF; } +<rules_cond>[ ]+                    { } +<rules_cond>"("                     { return EXPR_START; } +<rules_cond>[A-Za-z][A-Za-z0-9]*    { d2c_lval.string = strdup(yytext); return NAME; } +<rules_cond>"=="                    { return EQUAL; } +<rules_cond>"'"                     { BEGIN(rules_cond_binval); } +<rules_cond_binval>[01][01]*        { d2c_lval.string = strdup(yytext); return BINVAL; } +<rules_cond_binval>"'"              { BEGIN(rules_cond); } +<rules_cond>")"                     { return EXPR_END; } +<rules_cond>"&&"                    { return AND; } + +<rules_cond>";"                     { BEGIN(rules_action); return THEN; } +<rules_action>[ ]+                  { } +<rules_action>"see "                { BEGIN(rules_actin_see); return SEE; } +<rules_actin_see>[^\n]*             { d2c_lval.cstring = yytext; BEGIN(rules_content); return INS_DETAILS; } + + +%% + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Tente de libérer autant de mémoire que possible...           * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void free_flex_memory(void) +{ +    yy_delete_buffer(YY_CURRENT_BUFFER); + +}  | 
