From b77dcf34b9b2308978e1c6333b34cde9f0e27a8c Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 8 Sep 2008 22:53:49 +0000
Subject: Handled four kinds of the 'test' opcode.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@27 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                  |  23 ++-
 src/arch/x86/Makefile.am   |   1 +
 src/arch/x86/instruction.h |   6 +
 src/arch/x86/op_mov.c      |  22 +--
 src/arch/x86/opcodes.h     |  12 ++
 src/arch/x86/operand.c     | 343 ++++++++++++++++++++++++++++++++++++++++++++-
 src/arch/x86/operand.h     |  16 +++
 src/arch/x86/processor.c   |  11 +-
 8 files changed, 418 insertions(+), 16 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7fd494f..0725005 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,25 @@
-2008-09-06  Cyrille Bagard <nocbos@gmail.com>
+2008-09-09  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/arch/x86/instruction.h:
+	Handle four kinds of the 'test' opcode.
+
+	* src/arch/x86/Makefile.am:
+	Add op_test.c to libarchx86_a_SOURCES.
+
+	* src/arch/x86/opcodes.h:
+	Register the new decoding functions.
+
+	* src/arch/x86/operand.c:
+	* src/arch/x86/operand.h:
+	Handle the r/m information in a clever way.
+
+	* src/arch/x86/op_mov.c:
+	Reorganize the code ; this must be improved.
+
+	* src/arch/x86/processor.c:
+	Register the new decoding functions.
+
+2008-09-07  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/arch/x86/op_lea.c:
 	* src/arch/x86/op_mov.c:
diff --git a/src/arch/x86/Makefile.am b/src/arch/x86/Makefile.am
index 238cf61..b074f69 100644
--- a/src/arch/x86/Makefile.am
+++ b/src/arch/x86/Makefile.am
@@ -21,6 +21,7 @@ libarchx86_a_SOURCES =					\
 	op_ret.c							\
 	op_sbb.c							\
 	op_sub.c							\
+	op_test.c							\
 	op_xor.c							\
 	opcodes.h							\
 	operand.h operand.c					\
diff --git a/src/arch/x86/instruction.h b/src/arch/x86/instruction.h
index 1a9b6d4..38315d9 100644
--- a/src/arch/x86/instruction.h
+++ b/src/arch/x86/instruction.h
@@ -88,12 +88,18 @@ typedef enum _X86Opcodes
     X86_OP_SUB8_REG1632,                    /* sub ([0x66] 0x83)           */
     X86_OP_XOR8_REG1632,                    /* xor ([0x66] 0x83)           */
 
+    X86_OP_TEST_RM8,                        /* test ([0x66] 0x84)          */
+    X86_OP_TEST_RM1632,                     /* test ([0x66] 0x85)          */
+
     X86_OP_MOV_FROM_CONTENT1632,            /* mov ([0x66] 0x8b)           */
 
     X86_OP_LEA,                             /* lea ([0x66] 0x8d)           */   /* 66 ? */
 
     X86_OP_NOP,                             /* nop (0x90)                  */
 
+    X86_OP_TEST_AL,                         /* test ([0x66] 0xa8)          */
+    X86_OP_TEST_E_AX,                       /* test ([0x66] 0xa9)          */
+
     X86_OP_MOV_E_AX,                        /* mov ([0x66] 0xb8)           */
     X86_OP_MOV_E_CX,                        /* mov ([0x66] 0xb9)           */
     X86_OP_MOV_E_DX,                        /* mov ([0x66] 0xba)           */
diff --git a/src/arch/x86/op_mov.c b/src/arch/x86/op_mov.c
index db731bb..d0a1bfc 100644
--- a/src/arch/x86/op_mov.c
+++ b/src/arch/x86/op_mov.c
@@ -65,27 +65,27 @@ asm_x86_instr *read_instr_mov_with_reg1632(const uint8_t *data, off_t *pos, off_
 
     ASM_INSTRUCTION(result)->opcode = data[(*pos)++];
 
-    /* TODO ! */
-    if ((data[*pos] & 0xc0) != 0xc0)
-        return NULL;
-
-    reg1 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, true);
-    if (reg1 == NULL)
+    reg2 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, false);
+    if (reg2 == NULL)
     {
         free(result);
         return NULL;
     }
 
-    reg2 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, false);
-    if (reg2 == NULL)
+    if ((data[*pos] & 0xc0) == 0xc0)
+    {
+        reg1 = x86_create_reg1632_operand_from_modrm(data[*pos], oprsize == AOS_32_BITS, true);
+        (*pos)++;
+    }
+    else reg1 = x86_create_content1632_operand(data, pos, len, oprsize == AOS_32_BITS, true);
+
+    if (reg1 == NULL)
     {
         free(result);
-        free(reg1);
+        free(reg2);
         return NULL;
     }
 
-    (*pos)++;
-
     ASM_INSTRUCTION(result)->operands = (asm_operand **)calloc(2, sizeof(asm_operand *));
     ASM_INSTRUCTION(result)->operands_count = 2;
 
diff --git a/src/arch/x86/opcodes.h b/src/arch/x86/opcodes.h
index 1d3611f..64614dc 100644
--- a/src/arch/x86/opcodes.h
+++ b/src/arch/x86/opcodes.h
@@ -103,6 +103,18 @@ asm_x86_instr *read_instr_sbb8_with_reg1632(const uint8_t *, off_t *, off_t, uin
 /* Décode une instruction de type 'sub'. */
 asm_x86_instr *read_instr_sub8_with_reg1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
 
+/* Décode une instruction de type 'test al, ...' (8 bits). */
+asm_x86_instr *read_instr_test_al(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
+/* Décode une instruction de type 'test [e]ax, ...' (16/32b). */
+asm_x86_instr *read_instr_test_e_ax(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
+/* Décode une instruction de type 'test' (8 bits). */
+asm_x86_instr *read_instr_test_rm8(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
+/* Décode une instruction de type 'test' (16 ou 32 bits). */
+asm_x86_instr *read_instr_test_rm1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
+
 /* Décode une instruction de type 'xor' (16 ou 32 bits). */
 asm_x86_instr *read_instr_xor_with_reg1632(const uint8_t *, off_t *, off_t, uint64_t, const asm_x86_processor *);
 
diff --git a/src/arch/x86/operand.c b/src/arch/x86/operand.c
index ada66f0..a232211 100644
--- a/src/arch/x86/operand.c
+++ b/src/arch/x86/operand.c
@@ -178,7 +178,15 @@ bool get_x86_register(x86_register *reg, AsmOperandSize size, uint8_t value)
     switch (size)
     {
         case AOS_8_BITS:
-            return false;
+            switch (value)
+            {
+                case 0 ... 7:
+                    reg->reg8 = (X868bRegister)value;
+                    break;
+                default:
+                    return false;
+                    break;
+            }
             break;
 
         case AOS_16_BITS:
@@ -418,6 +426,339 @@ asm_x86_operand *x86_create_content1632_operand(const uint8_t *data, off_t *pos,
 }
 
 
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : data  = donnée à analyser.                                   *
+*                first = indique la partie du ModR/M à traiter.               *
+*                                                                             *
+*  Description : Crée une opérande renvoyant vers un registre 8 bits.         *
+*                                                                             *
+*  Retour      : Opérande mise en place ou NULL.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+asm_x86_operand *x86_create_r8_operand(uint8_t data, bool first)
+{
+    asm_x86_operand *result;                /* Registre à retourner        */
+    uint8_t reg;                            /* Transcription du registre   */
+
+    if (first) reg = data & 0x07;
+    else reg = (data & 0x38) >> 3;
+
+    result = create_new_x86_operand();
+
+    ASM_OPERAND(result)->type = AOT_REG;
+    ASM_OPERAND(result)->size = AOS_8_BITS;
+
+    if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, reg))
+    {
+        free(result);
+        return NULL;
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : data  = flux de données à analyser.                          *
+*                pos   = position courante dans ce flux. [OUT]                *
+*                len   = taille totale des données à analyser.                *
+*                first = indique la partie du ModR/M à traiter.               *
+*                                                                             *
+*  Description : Crée une opérande à partir d'un registre/une mémoire 8 bits. *
+*                                                                             *
+*  Retour      : Opérande mise en place ou NULL.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+asm_x86_operand *x86_create_rm8_operand(const uint8_t *data, off_t *pos, off_t len, bool first)
+{
+    asm_x86_operand *result;                /* Registre à retourner        */
+    uint8_t mod;                            /* Modificateur présent        */
+
+    /* Registre simple... */
+
+    result = x86_create_r8_operand(data[*pos], first);
+    if (result == NULL) return NULL;
+
+    mod = (data[*pos] & 0xc0);
+
+    (*pos)++;
+
+    if (mod == 0xc0) return result;
+
+    result->content = true;
+
+    /* Vieille astuce de l'emplacement mémoire fixe ? */
+    if (result->rindex.reg8 == X86_REG8_CH && mod == 0x00)
+    {
+        free(result);
+
+        result = create_new_x86_operand();
+        if (!fill_imm_operand(ASM_OPERAND(result), AOS_8_BITS, data, pos, len))
+        {
+            free(result);
+            return NULL;
+        }
+
+        return result;
+
+    }
+
+    /* A la recherche d'un SIB */
+    if (result->rindex.reg8 == X86_REG8_AH)
+    {
+        if (!get_x86_register(&result->rbase, ASM_OPERAND(result)->size, data[*pos] & 0x07))
+        {
+            free(result);
+            return NULL;
+        }
+
+        if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, (data[*pos] & 0x38) >> 3))
+        {
+            free(result);
+            return NULL;
+        }
+
+        result->scale = ((data[*pos] & 0xc0) >> 6);
+
+        if (result->rindex.reg8 == X86_REG8_AH)
+        {
+            result->rindex.reg8 = result->rbase.reg8;
+            result->rbase.reg8 = X86_REG8_NONE;
+        }
+
+        (*pos)++;
+
+    }
+
+    /* Décallage supplémentaire ? */
+    switch (mod)
+    {
+        case 0x00:
+            if (result->rbase.reg8 == X86_REG8_CH)
+            {
+                result->rbase.reg8 = X86_REG8_NONE;
+
+                result->displacement = create_new_x86_operand();
+                if (!fill_imm_operand(ASM_OPERAND(result->displacement), ASM_OPERAND(result)->size, data, pos, len))
+                {
+                    free(result->displacement);
+                    free(result);
+                    return NULL;
+                }
+
+            }
+            break;
+
+        case 0x40:
+            result->displacement = create_new_x86_operand();
+            if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len))
+            {
+                free(result->displacement);
+                free(result);
+                return NULL;
+            }
+            break;
+
+        case 0x80:
+            result->displacement = create_new_x86_operand();
+            if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len))
+            {
+                free(result->displacement);
+                free(result);
+                return NULL;
+            }
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : data     = donnée à analyser.                                *
+*                is_reg32 = indique si le registre est un registre 32 bits.   *
+*                first    = indique la partie du ModR/M à traiter.            *
+*                                                                             *
+*  Description : Crée une opérande renvoyant vers un registre 16 ou 32 bits.  *
+*                                                                             *
+*  Retour      : Opérande mise en place ou NULL.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+asm_x86_operand *x86_create_r1632_operand(uint8_t data, bool is_reg32, bool first)
+{
+    asm_x86_operand *result;                /* Registre à retourner        */
+    uint8_t reg;                            /* Transcription du registre   */
+
+    if (first) reg = data & 0x07;
+    else reg = (data & 0x38) >> 3;
+
+    result = create_new_x86_operand();
+
+    ASM_OPERAND(result)->type = AOT_REG;
+    ASM_OPERAND(result)->size = (is_reg32 ? AOS_32_BITS : AOS_16_BITS);
+
+    if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, reg))
+    {
+        free(result);
+        return NULL;
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : data     = flux de données à analyser.                       *
+*                pos      = position courante dans ce flux. [OUT]             *
+*                len      = taille totale des données à analyser.             *
+*                is_reg32 = indique si le registre est un registre 32 bits.   *
+*                first    = indique la partie du ModR/M à traiter.            *
+*                                                                             *
+*  Description : Crée une opérande à partir d'un registre/une mémoire 16/32b. *
+*                                                                             *
+*  Retour      : Opérande mise en place ou NULL.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+asm_x86_operand *x86_create_rm1632_operand(const uint8_t *data, off_t *pos, off_t len, bool is_reg32, bool first)
+{
+    asm_x86_operand *result;                /* Registre à retourner        */
+    uint8_t mod;                            /* Modificateur présent        */
+
+    /* Registre simple... */
+
+    result = x86_create_r1632_operand(data[*pos], is_reg32, first);
+    if (result == NULL) return NULL;
+
+    mod = (data[*pos] & 0xc0);
+
+    (*pos)++;
+
+    if (mod == 0xc0) return result;
+
+    result->content = true;
+
+    /* Vieille astuce de l'emplacement mémoire fixe ? */
+    if (result->rindex.reg32 == X86_REG32_EBP && mod == 0x00)
+    {
+        free(result);
+
+        result = create_new_x86_operand();
+        if (!fill_imm_operand(ASM_OPERAND(result), AOS_32_BITS/* FIXME ? */, data, pos, len))
+        {
+            free(result);
+            return NULL;
+        }
+
+        return result;
+
+    }
+
+    /* A la recherche d'un SIB */
+    if (result->rindex.reg32 == X86_REG32_ESP)
+    {
+        if (!get_x86_register(&result->rbase, ASM_OPERAND(result)->size, data[*pos] & 0x07))
+        {
+            free(result);
+            return NULL;
+        }
+
+        if (!get_x86_register(&result->rindex, ASM_OPERAND(result)->size, (data[*pos] & 0x38) >> 3))
+        {
+            free(result);
+            return NULL;
+        }
+
+        result->scale = ((data[*pos] & 0xc0) >> 6);
+
+        if (result->rindex.reg32 == X86_REG32_ESP)
+        {
+            result->rindex.reg32 = result->rbase.reg32;
+            result->rbase.reg32 = X86_REG32_NONE;
+        }
+
+        (*pos)++;
+
+    }
+
+    /* Décallage supplémentaire ? */
+    switch (mod)
+    {
+        case 0x00:
+            if (result->rbase.reg32 == X86_REG32_EBP)
+            {
+                result->rbase.reg32 = X86_REG32_NONE;
+
+                result->displacement = create_new_x86_operand();
+                if (!fill_imm_operand(ASM_OPERAND(result->displacement), ASM_OPERAND(result)->size, data, pos, len))
+                {
+                    free(result->displacement);
+                    free(result);
+                    return NULL;
+                }
+
+            }
+            break;
+
+        case 0x40:
+            result->displacement = create_new_x86_operand();
+            if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_8_BITS, data, pos, len))
+            {
+                free(result->displacement);
+                free(result);
+                return NULL;
+            }
+            break;
+
+        case 0x80:
+            result->displacement = create_new_x86_operand();
+            if (!fill_imm_operand(ASM_OPERAND(result->displacement), AOS_32_BITS, data, pos, len))
+            {
+                free(result->displacement);
+                free(result);
+                return NULL;
+            }
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : reg    = registre à imprimer.                                *
diff --git a/src/arch/x86/operand.h b/src/arch/x86/operand.h
index fbaba57..c330b8e 100644
--- a/src/arch/x86/operand.h
+++ b/src/arch/x86/operand.h
@@ -51,6 +51,22 @@ asm_x86_operand *x86_create_reg1632_operand_from_modrm(uint8_t, bool, bool);
 /* Crée une opérande renvoyant vers un contenu 16 ou 32 bits. */
 asm_x86_operand *x86_create_content1632_operand(const uint8_t *, off_t *, off_t, bool, bool);
 
+
+
+/* Crée une opérande renvoyant vers un registre 8 bits. */
+asm_x86_operand *x86_create_r8_operand(uint8_t, bool);
+
+/* Crée une opérande à partir d'un registre/une mémoire 8 bits. */
+asm_x86_operand *x86_create_rm8_operand(const uint8_t *, off_t *, off_t, bool);
+
+/* Crée une opérande renvoyant vers un registre 16 ou 32 bits. */
+asm_x86_operand *x86_create_r1632_operand(uint8_t, bool, bool);
+
+/* Crée une opérande à partir d'un registre/une mémoire 16/32b. */
+asm_x86_operand *x86_create_rm1632_operand(const uint8_t *, off_t *, off_t, bool, bool);
+
+
+
 /* Traduit une opérande de registre en texte. */
 void x86_print_reg_operand(const asm_x86_operand *, char *, size_t, AsmSyntax);
 
diff --git a/src/arch/x86/processor.c b/src/arch/x86/processor.c
index 118dbd6..3ca14b9 100644
--- a/src/arch/x86/processor.c
+++ b/src/arch/x86/processor.c
@@ -234,9 +234,6 @@ void x86_register_instructions(asm_x86_processor *proc)
 
     register_opcode(proc->opcodes[X86_OP_PUSH_IMM1632], 0x66, 0x68, "push", read_instr_push_imm1632);
 
-
-    register_opcode(proc->opcodes[X86_OP_MOV_REG1632], 0x66, 0x89, "mov", read_instr_mov_with_reg1632);
-
     register_opcode_with_ext(proc->opcodes[X86_OP_ADD8_REG1632], 0x66, 0x83, 0, "add", read_instr_add8_with_reg1632);
     register_opcode_with_ext(proc->opcodes[X86_OP_OR8_REG1632], 0x66, 0x83, 1, "or", read_instr_or8_with_reg1632);
     register_opcode_with_ext(proc->opcodes[X86_OP_ADC8_REG1632], 0x66, 0x83, 2, "adc", read_instr_adc8_with_reg1632);
@@ -245,12 +242,20 @@ void x86_register_instructions(asm_x86_processor *proc)
     register_opcode_with_ext(proc->opcodes[X86_OP_SUB8_REG1632], 0x66, 0x83, 5, "sub", read_instr_sub8_with_reg1632);
     register_opcode_with_ext(proc->opcodes[X86_OP_XOR8_REG1632], 0x66, 0x83, 6, "xor", read_instr_xor8_with_reg1632);
 
+    register_opcode(proc->opcodes[X86_OP_TEST_RM8], 0x00, 0x84, "test", read_instr_test_rm8);
+    register_opcode(proc->opcodes[X86_OP_TEST_RM1632], 0x66, 0x85, "test", read_instr_test_rm1632);
+
+    register_opcode(proc->opcodes[X86_OP_MOV_REG1632], 0x66, 0x89, "mov", read_instr_mov_with_reg1632);
+
     register_opcode(proc->opcodes[X86_OP_MOV_FROM_CONTENT1632], 0x66, 0x8b, "mov", read_instr_mov_from_content_1632);
 
     register_opcode(proc->opcodes[X86_OP_LEA], 0x66, 0x8d, "lea", read_instr_lea);
 
     register_opcode(proc->opcodes[X86_OP_NOP], 0x00, 0x90, "nop", read_instr_nop);
 
+    register_opcode(proc->opcodes[X86_OP_TEST_AL], 0x00, 0xa8, "test", read_instr_test_al);
+    register_opcode(proc->opcodes[X86_OP_TEST_E_AX], 0x66, 0xa9, "test", read_instr_test_e_ax);
+
     register_opcode(proc->opcodes[X86_OP_MOV_E_AX], 0x66, 0xb8, "mov", read_instr_mov_to_1632);
     register_opcode(proc->opcodes[X86_OP_MOV_E_CX], 0x66, 0xb9, "mov", read_instr_mov_to_1632);
     register_opcode(proc->opcodes[X86_OP_MOV_E_DX], 0x66, 0xba, "mov", read_instr_mov_to_1632);
-- 
cgit v0.11.2-87-g4458