/* OpenIDA - Outil d'analyse de fichiers binaires
 * operand.h - prototypes pour la gestion des operandes de l'architecture x86
 *
 * Copyright (C) 2008-2010 Cyrille Bagard
 *
 *  This file is part of OpenIDA.
 *
 *  OpenIDA is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  OpenIDA is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */


#ifndef _ARCH_X86_OPERAND_H
#define _ARCH_X86_OPERAND_H


#include <stdbool.h>


#include "../immediate.h"
#include "../instruction.h"
#include "registers.h"



/* ---------------------- COQUILLE VIDE POUR LES OPERANDES X86 ---------------------- */


#define G_TYPE_X86_OPERAND                  g_x86_operand_get_type()
#define G_X86_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_x86_operand_get_type(), GX86Operand))
#define G_IS_X86_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_x86_operand_get_type()))
#define G_X86_OPERAND_GET_IFACE(inst)       (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_x86_operand_get_type(), GX86OperandIface))


/* Définition d'un opérande de x86 (instance) */
typedef struct _GX86Operand GX86Operand;

/* Définition d'un opérande de x86 (classe) */
typedef struct _GX86OperandClass GX86OperandClass;


/* Indique le type défini par la GLib pour un opérande de x86. */
GType g_x86_operand_get_type(void);



/* ------------------------ OPERANDES VISANT UN REGISTRE X86 ------------------------ */


#define G_TYPE_X86_REGISTER_OPERAND                  g_x86_register_operand_get_type()
#define G_X86_REGISTER_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_x86_register_operand_get_type(), GX86RegisterOperand))
#define G_IS_X86_REGISTER_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_x86_register_operand_get_type()))
#define G_X86_REGISTER_OPERAND_GET_IFACE(inst)       (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_x86_register_operand_get_type(), GX86RegisterOperandIface))


/* Définition d'un opérande visant un registre x86 (instance) */
typedef struct _GX86RegisterOperand GX86RegisterOperand;

/* Définition d'un opérande visant un registre x86 (classe) */
typedef struct _GX86RegisterOperandClass GX86RegisterOperandClass;


/* Indique le type défini par la GLib pour un opérande de registre x86. */
GType g_x86_register_operand_get_type(void);

/* Crée un opérande visant un registre x86. */
GArchOperand *g_x86_register_operand_new_from_opcode(const bin_t *, off_t *, off_t, MemoryDataSize, bin_t);

/* Crée un opérande visant un registre x86. */
GArchOperand *g_x86_register_operand_new_from_mod_rm(const bin_t *, off_t *, off_t, MemoryDataSize, bool);

/* Crée un opérande visant un registre x86 donné. */
GArchOperand *g_x86_register_operand_new_from_index(bin_t, MemoryDataSize);



/* ----------------------- OPERANDES COMPLEXES DE TYPE MOD/RM ----------------------- */


#define G_TYPE_X86_MOD_RM_OPERAND                  g_x86_mod_rm_operand_get_type()
#define G_X86_MOD_RM_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_x86_mod_rm_operand_get_type(), GX86ModRMOperand))
#define G_IS_X86_MOD_RM_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_x86_mod_rm_operand_get_type()))
#define G_X86_MOD_RM_OPERAND_GET_IFACE(inst)       (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_x86_mod_rm_operand_get_type(), GX86ModRMOperandIface))


/* Définition d'un opérande x86 de type ModRM (instance) */
typedef struct _GX86ModRMOperand GX86ModRMOperand;

/* Définition d'un opérande x86 de type ModRM (classe) */
typedef struct _GX86ModRMOperandClass GX86ModRMOperandClass;


/* Indique le type défini par la GLib pour un opérande x86 de type ModRM. */
GType g_x86_mod_rm_operand_get_type(void);

/* Crée un opérande x86 de type ModRM. */
GArchOperand *g_x86_mod_rm_operand_new(const bin_t *, off_t *, off_t, MemoryDataSize);

/* Fournit l'indice et l'échelle d'un opérande x86 ModRM. */
void g_x86_mod_rm_operand_get_scale_and_index(const GX86ModRMOperand *operand, uint8_t *, const GX86Register **);

/* Fournit le registre de base d'un opérande x86 ModRM. */
const GX86Register *g_x86_mod_rm_operand_get_base(const GX86ModRMOperand *);

/* Fournit le décallage supplémentaire d'un opérande x86 ModRM. */
const GImmOperand *g_x86_mod_rm_operand_get_displacement(const GX86ModRMOperand *);



/* ------------------------- OPERANDES D'ADRESSES RELATIVES ------------------------- */


#define G_TYPE_X86_RELATIVE_OPERAND                  g_x86_relative_operand_get_type()
#define G_X86_RELATIVE_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_x86_relative_operand_get_type(), GX86RelativeOperand))
#define G_IS_X86_RELATIVE_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_x86_relative_operand_get_type()))
#define G_X86_RELATIVE_OPERAND_GET_IFACE(inst)       (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_x86_relative_operand_get_type(), GX86RelativeOperandIface))


/* Définition d'un opérande x86 d'adresse relative (instance) */
typedef struct _GX86RelativeOperand GX86RelativeOperand;

/* Définition d'un opérande x86 d'adresse relative (classe) */
typedef struct _GX86RelativeOperandClass GX86RelativeOperandClass;


/* Indique le type défini par la GLib pour un opérande x86 d'adresse relative. */
GType g_x86_relative_operand_get_type(void);

/* Crée un opérande X86 d'adresse relative. */
GArchOperand *g_x86_relative_operand_new(const bin_t *, off_t *, off_t, MemoryDataSize, vmpa_t);

/* Fournit l'adresse représentée par une opérande X86. */
const GImmOperand *g_x86_relative_operand_get_value(const GX86RelativeOperand *);



/* ------------------------ OPERANDES D'EMPLACEMENTS MEMOIRE ------------------------ */


#define G_TYPE_X86_MOFFS_OPERAND                  g_x86_moffs_operand_get_type()
#define G_X86_MOFFS_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_x86_moffs_operand_get_type(), GX86MoffsOperand))
#define G_IS_X86_MOFFS_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_x86_moffs_operand_get_type()))
#define G_X86_MOFFS_OPERAND_GET_IFACE(inst)       (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_x86_moffs_operand_get_type(), GX86MoffsOperandIface))


/* Définition d'un opérande visant un emplacement mémoire x86 (instance) */
typedef struct _GX86MOffsOperand GX86MOffsOperand;

/* Définition d'un opérande visant un emplacement mémoire x86 (classe) */
typedef struct _GX86MOffsOperandClass GX86MOffsOperandClass;


/* Indique le type défini par la GLib pour un opérande d'emplacement mémoire x86. */
GType g_x86_moffs_operand_get_type(void);

/* Crée un opérande d'emplacement mémoire x86. */
GArchOperand *g_x86_moffs_operand_new(const bin_t *, off_t *, off_t, MemoryDataSize);



/* ---------------------- OPERANDES DE MANIPULATION DE DONNEES ---------------------- */


#define G_TYPE_X86_DATA_OPERAND                  g_x86_data_operand_get_type()
#define G_X86_DATA_OPERAND(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), g_x86_data_operand_get_type(), GX86DataOperand))
#define G_IS_X86_DATA_OPERAND(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_x86_data_operand_get_type()))
#define G_X86_DATA_OPERAND_GET_IFACE(inst)       (G_TYPE_INSTANCE_GET_INTERFACE((inst), g_x86_data_operand_get_type(), GX86DataOperandIface))


/* Définition d'un opérande x86 de manipulation de données (instance) */
typedef struct _GX86DataOperand GX86DataOperand;

/* Définition d'un opérande x86 de manipulation de données (classe) */
typedef struct _GX86DataOperandClass GX86DataOperandClass;


/* Indique le type défini par la GLib pour un opérande x86 de manipulation de données. */
GType g_x86_data_operand_get_type(void);

/* Crée un opérande x86 de manipulation de données. */
GArchOperand *g_x86_data_operand_new(MemoryDataSize, bool);



/* ------------------------- AIDE A LA CREATION D'OPERANDES ------------------------- */


/* Construction d'identifiants typés */

#define X86_OTP_IMM_TYPE    0x8000
#define X86_OTP_REG_TYPE    0x4000
#define X86_OTP_RM_TYPE     0x2000
#define X86_OTP_DATA_TYPE   0x1000

#define X86_OTP_IMM(b)  X86_OTP_IMM_TYPE  | (1 << b)
#define X86_OTP_REG(b)  X86_OTP_REG_TYPE  | (1 << b)
#define X86_OTP_RM(b)   X86_OTP_RM_TYPE   | (1 << b)
#define X86_OTP_DATA(b) X86_OTP_DATA_TYPE | (1 << b)

/* Types d'opérandes supportés */
typedef enum _X86OperandType
{
    X86_OTP_NONE        = 0,                /* Aucun opérande de prévu     */

    X86_OTP_IMM8        = X86_OTP_IMM(1),   /* Valeur immédiate sur 8 bits */
    X86_OTP_IMM16       = X86_OTP_IMM(2),   /* Valeur immédiate sur 16b    */
    X86_OTP_IMM1632     = X86_OTP_IMM(3),   /* Valeur immédiate sur 16/32b */
    X86_OTP_MOFFS8      = X86_OTP_IMM(4),   /* Décallage immédiat 8 bits   */
    X86_OTP_MOFFS1632   = X86_OTP_IMM(5),   /* Décallage immédiat 16/32b   */
    X86_OTP_REL8        = X86_OTP_IMM(6),   /* Adresse relative 8 bits     */
    X86_OTP_REL1632     = X86_OTP_IMM(7),   /* Adresse relative 16/32 bits */

    X86_OTP_R8          = X86_OTP_REG(1),   /* Registre 8 bits             */
    X86_OTP_R1632       = X86_OTP_REG(2),   /* Registre 16 ou 32 bits      */
    X86_OTP_OP_R8       = X86_OTP_REG(3),   /* Registre 8 bits             */
    X86_OTP_OP_R1632    = X86_OTP_REG(4),   /* Registre 16 ou 32 bits      */

    X86_OTP_RM8         = X86_OTP_RM(1),    /* Registre 8 bits ou mémoire  */
    X86_OTP_RM16        = X86_OTP_RM(2),    /* Registre 16 bits ou mémoire */
    X86_OTP_RM1632      = X86_OTP_RM(3),    /* Registre 16/32b ou mémoire  */

    X86_OTP_DST_8       = X86_OTP_DATA(1),  /* Emplacement sur 8 bits      */
    X86_OTP_DST_1632    = X86_OTP_DATA(2),  /* Emplacement sur 16/32 bits  */
    X86_OTP_SRC_8       = X86_OTP_DATA(3),  /* Emplacement sur 8 bits      */
    X86_OTP_SRC_1632    = X86_OTP_DATA(4),  /* Emplacement sur 16/32 bits  */

    X86_OTP_ONE         = 0x0ffc,           /* Valeur immédiate "1"        */
    X86_OTP_CL          = 0x0ffd,           /* Registre cl                 */
    X86_OTP_AL          = 0x0ffe,           /* Registre al                 */
    X86_OTP_E_AX        = 0x0fff            /* Registre eax ou ax          */

} X86OperandType;


/* Nombre maximal d'opérande */
#define MAX_OPERANDS 3


#define x86_read_one_operand(instr, data, pos, len, ...) _x86_read_operands(instr, data, pos, len, 1, __VA_ARGS__)
#define x86_read_two_operands(instr, data, pos, len, ...) _x86_read_operands(instr, data, pos, len, 2, __VA_ARGS__)
#define x86_read_three_operands(instr, data, pos, len, ...) _x86_read_operands(instr, data, pos, len, 3, __VA_ARGS__)

/* Procède à la lecture de n opérandes donnés. */
bool _x86_read_operands(GArchInstruction *, const bin_t *, off_t *, off_t, unsigned int, ...);



#endif  /* _ARCH_X86_OPERAND_H */