summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog53
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac3
-rw-r--r--src/analysis/disass/fetch.c4
-rw-r--r--src/arch/arm/instruction.c8
-rw-r--r--src/arch/arm/instruction.h4
-rw-r--r--src/arch/arm/v7/Makefile.am6
-rw-r--r--src/arch/arm/v7/arm.c3
-rw-r--r--src/arch/arm/v7/helpers.c58
-rw-r--r--src/arch/arm/v7/helpers.h40
-rw-r--r--src/arch/arm/v7/instruction.c10
-rw-r--r--src/arch/arm/v7/instruction.h7
-rw-r--r--src/arch/arm/v7/opcodes/Makefile.am15
-rw-r--r--src/arch/arm/v7/opdefs/Makefile.am37
-rw-r--r--src/arch/arm/v7/opdefs/mov_A88104.d47
-rw-r--r--src/arch/arm/v7/opdefs/subs_B9320.d44
-rw-r--r--src/arch/arm/v7/processor.c12
-rw-r--r--src/arch/register-int.h29
-rw-r--r--src/arch/register.c202
-rw-r--r--src/arch/register.h39
-rw-r--r--tools/Makefile.am25
-rw-r--r--tools/coder.c1878
-rw-r--r--tools/coder.h158
-rw-r--r--tools/d2c.mk22
-rw-r--r--tools/d2c_gram.y329
-rw-r--r--tools/d2c_tok.l165
26 files changed, 3184 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 8aa8068..6af7fa3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
+
+}