From a5e162d47a574f334b172dfee3128a40e8d52fb3 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 7 Oct 2014 22:07:27 +0000 Subject: Created a compiler for architecture instruction definitions. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@410 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 53 + Makefile.am | 2 +- configure.ac | 3 + src/analysis/disass/fetch.c | 4 +- src/arch/arm/instruction.c | 8 +- src/arch/arm/instruction.h | 4 +- src/arch/arm/v7/Makefile.am | 6 +- src/arch/arm/v7/arm.c | 3 +- src/arch/arm/v7/helpers.c | 58 ++ src/arch/arm/v7/helpers.h | 40 + src/arch/arm/v7/instruction.c | 10 +- src/arch/arm/v7/instruction.h | 7 +- src/arch/arm/v7/opcodes/Makefile.am | 15 + src/arch/arm/v7/opdefs/Makefile.am | 37 + src/arch/arm/v7/opdefs/mov_A88104.d | 47 + src/arch/arm/v7/opdefs/subs_B9320.d | 44 + src/arch/arm/v7/processor.c | 12 +- src/arch/register-int.h | 29 + src/arch/register.c | 202 ++++ src/arch/register.h | 39 + tools/Makefile.am | 25 + tools/coder.c | 1878 +++++++++++++++++++++++++++++++++++ tools/coder.h | 158 +++ tools/d2c.mk | 22 + tools/d2c_gram.y | 329 ++++++ tools/d2c_tok.l | 165 +++ 26 files changed, 3184 insertions(+), 16 deletions(-) create mode 100644 src/arch/arm/v7/helpers.c create mode 100644 src/arch/arm/v7/helpers.h create mode 100644 src/arch/arm/v7/opcodes/Makefile.am create mode 100644 src/arch/arm/v7/opdefs/Makefile.am create mode 100644 src/arch/arm/v7/opdefs/mov_A88104.d create mode 100644 src/arch/arm/v7/opdefs/subs_B9320.d create mode 100644 tools/Makefile.am create mode 100644 tools/coder.c create mode 100644 tools/coder.h create mode 100644 tools/d2c.mk create mode 100644 tools/d2c_gram.y create mode 100644 tools/d2c_tok.l diff --git a/ChangeLog b/ChangeLog index 8aa8068..6af7fa3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +14-10-08 Cyrille Bagard + + * 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 * 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 +#include #include #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 +#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 . + */ + + +#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 . + */ + + +#ifndef _ARCH_ARM_V7_HELPERS_H +#define _ARCH_ARM_V7_HELPERS_H + + +#include + + +#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 +#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\ \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 . + */ + + +@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} + + @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 . + */ + + +@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} <#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 . + */ + + +#include "coder.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/* -------------------------- 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 .\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 . + */ + + +#ifndef _ARCH_ARM_V7_OPDEFS_CODER_H +#define _ARCH_ARM_V7_OPDEFS_CODER_H + + +#include + + + +/* 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 +#include +#include +#include +#include + + +#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 COPYRIGHT INS_NAME +%type INS_DETAILS + +%type NUMBER + +%type NAME +%type SIZE BIT + +%type OPERAND_INTERNAL OPERAND_VISIBLE + +%type ARG + +%type rule_cond +%type BINVAL +%type 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 \t\tSpecify the main output directory.\n"); + printf("\t-a | --arch \t\tDefine the archicture to handle.\n"); + printf("\t-H | --header \t\tSet the base of the #ifndef / #define game.\n"); + printf("\t-e | --encoding \tDefine encoding prefixes for files.\n"); + printf("\t-m | --macro \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 +#include + + +/* 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); } +"*/" { BEGIN(INITIAL); } +[^*\n] { } +"Copyright"[^\n]* { d2c_lval.string = strdup(yytext); return COPYRIGHT; } +"*" { } +"\n" { } + + +"@title" { BEGIN(ins_name); return TITLE; } + +[ ][A-Za-z-]+ { d2c_lval.string = strdup(yytext + 1); BEGIN(try_details); return INS_NAME; } +[ ] { BEGIN(ins_details); } +[\n] { BEGIN(INITIAL); } + +[^\n]* { d2c_lval.cstring = yytext; return INS_DETAILS; } +[\n] { BEGIN(INITIAL); } + + + +"@encoding" { BEGIN(encoding); return ENCODING; } + +[ ] { } +"(" { BEGIN(encoding_type); } + +"T" { return THUMB; } +"A" { return ARCH; } +[0-9] { d2c_lval.integer = atoi(yytext); return NUMBER; } +")" { BEGIN(encoding); } + +"{" { BEGIN(encoding_content); } +[ \t\n]+ { } +"}" { BEGIN(INITIAL); } + + + +"@half" { BEGIN(encoding_bits); return HALF; } +"@word" { BEGIN(encoding_bits); return WORD; } + +" " { } +"\n" { BEGIN(encoding_content); } +[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } + +"(" { BEGIN(encoding_bits_size); } +[0-9]+ { d2c_lval.integer = atoi(yytext); return SIZE; } +")" { BEGIN(encoding_bits); } + +[01] { d2c_lval.integer = atoi(yytext); return BIT; } + + + +"@syntax" { BEGIN(syntax); return SYNTAX; } + +[ ]+ { } +"\n" { BEGIN(encoding_content); } + +"{" { BEGIN(syntax_int); } +[^ \n}]+ { d2c_lval.string = strdup(yytext); return OPERAND_INTERNAL; } +"}" { BEGIN(syntax); } + +"<" { BEGIN(syntax_ext); } +[^ \n>]+ { d2c_lval.string = strdup(yytext); return OPERAND_VISIBLE; } +">" { BEGIN(syntax); } + + + +"@conv" { BEGIN(conv_begin); return CONV; } +[ ]+ { } +"{" { BEGIN(conv_content); } +"}" { BEGIN(encoding_content); } + +[ \t\n]+ { } +[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } +"=" { return EQ; } + +"(" { BEGIN(conv_arg); } +[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return ARG; } +")" { BEGIN(conv_content); } + + + +"@rules" { BEGIN(rules_begin); return RULES; } +[ ]+ { } +"{" { BEGIN(rules_content); } +[ \t\n]+ { } +"}" { BEGIN(encoding_content); } + +"if" { BEGIN(rules_cond); return IF; } +[ ]+ { } +"(" { return EXPR_START; } +[A-Za-z][A-Za-z0-9]* { d2c_lval.string = strdup(yytext); return NAME; } +"==" { return EQUAL; } +"'" { BEGIN(rules_cond_binval); } +[01][01]* { d2c_lval.string = strdup(yytext); return BINVAL; } +"'" { BEGIN(rules_cond); } +")" { return EXPR_END; } +"&&" { return AND; } + +";" { BEGIN(rules_action); return THEN; } +[ ]+ { } +"see " { BEGIN(rules_actin_see); return 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); + +} -- cgit v0.11.2-87-g4458