/* OpenIDA - Outil d'analyse de fichiers binaires * operand.c - gestion des operandes de l'architecture x86 * * Copyright (C) 2008 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 . */ #include "operand.h" #include #include #include #include #include "../operand.h" #include "../operand-int.h" #include "../../common/extstr.h" /* ---------------------- COQUILLE VIDE POUR LES OPERANDES X86 ---------------------- */ /* Définition d'un opérande de x86 (instance) */ struct _GX86Operand { GArchOperand parent; /* Instance parente */ }; /* Définition d'un opérande de x86 (classe) */ struct _GX86OperandClass { GArchOperandClass parent; /* Classe parente */ }; /* Initialise la classe des opérandes x86 de base. */ static void g_x86_operand_class_init(GX86OperandClass *); /* Initialise une instance d'opérande de base pour x86. */ static void g_x86_operand_init(GX86Operand *); /* ------------------------ OPERANDES VISANT UN REGISTRE X86 ------------------------ */ /* Définition d'un opérande visant un registre x86 (instance) */ struct _GX86RegisterOperand { GX86Operand parent; /* Instance parente */ x86_register *reg; /* Registre représenté */ }; /* Définition d'un opérande visant un registre x86 (classe) */ struct _GX86RegisterOperandClass { GX86OperandClass parent; /* Classe parente */ }; /* Initialise la classe des opérandes de registre x86. */ static void g_x86_register_operand_class_init(GX86RegisterOperandClass *); /* Initialise une instance d'opérande de registre x86. */ static void g_x86_register_operand_init(GX86RegisterOperand *); /* Traduit un opérande en version humainement lisible. */ static char *g_x86_register_operand_get_text(const GX86RegisterOperand *, const GExeFormat *, AsmSyntax); /* ----------------------- OPERANDES COMPLEXES DE TYPE MOD/RM ----------------------- */ /* Définition d'un opérande x86 de type ModRM (instance) */ struct _GX86ModRMOperand { GX86Operand parent; /* Instance parente */ uint8_t scale; /* Puissance de deux */ x86_register *index; /* Registre servant d'indice */ x86_register *base; /* Registre de base */ GImmOperand *displacement; /* Décallage supplémentaire */ }; /* Définition d'un opérande x86 de type ModRM (classe) */ struct _GX86ModRMOperandClass { GX86OperandClass parent; /* Classe parente */ }; /* Initialise la classe des opérandes x86 de type ModRM. */ static void g_x86_mod_rm_operand_class_init(GX86ModRMOperandClass *); /* Initialise une instance d'opérande x86 de type ModRM. */ static void g_x86_mod_rm_operand_init(GX86ModRMOperand *); /* Traduit un opérande en version humainement lisible. */ static char *g_x86_mod_rm_operand_get_text(const GX86ModRMOperand *, const GExeFormat *, AsmSyntax); /* ------------------------- OPERANDES D'ADRESSES RELATIVES ------------------------- */ /* Définition d'un opérande x86 d'adresse relative (instance) */ struct _GX86RelativeOperand { GX86Operand parent; /* Instance parente */ GImmOperand *immediate; /* Adresse visée reconstituée */ }; /* Définition d'un opérande x86 d'adresse relative (classe) */ struct _GX86RelativeOperandClass { GX86OperandClass parent; /* Classe parente */ }; /* Initialise la classe des opérandes x86 d'adresse relative. */ static void g_x86_relative_operand_class_init(GX86RelativeOperandClass *); /* Initialise une instance d'opérande x86 d'adresse relative. */ static void g_x86_relative_operand_init(GX86RelativeOperand *); /* Traduit un opérande en version humainement lisible. */ static char *g_x86_relative_operand_get_text(const GX86RelativeOperand *, const GExeFormat *, AsmSyntax); /* ------------------------ OPERANDES D'EMPLACEMENTS MEMOIRE ------------------------ */ /* Définition d'un opérande visant un emplacement mémoire x86 (instance) */ struct _GX86MOffsOperand { GX86Operand parent; /* Instance parente */ GImmOperand *offset; /* Adresse mémoire visée */ }; /* Définition d'un opérande visant un emplacement mémoire x86 (classe) */ struct _GX86MOffsOperandClass { GX86OperandClass parent; /* Classe parente */ }; /* Initialise la classe des opérandes d'emplacement mémoire x86. */ static void g_x86_moffs_operand_class_init(GX86MOffsOperandClass *); /* Initialise une instance d'opérande d'emplacement mémoire x86. */ static void g_x86_moffs_operand_init(GX86MOffsOperand *); /* Traduit un opérande en version humainement lisible. */ static char *g_x86_moffs_operand_get_text(const GX86MOffsOperand *, const GExeFormat *, AsmSyntax); /* ---------------------------------------------------------------------------------- */ /* COQUILLE VIDE POUR LES OPERANDES X86 */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande de x86. */ G_DEFINE_TYPE(GX86Operand, g_x86_operand, G_TYPE_ARCH_OPERAND); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des opérandes x86 de base. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_operand_class_init(GX86OperandClass *klass) { } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande de base pour x86. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_operand_init(GX86Operand *operand) { } /* ---------------------------------------------------------------------------------- */ /* OPERANDES VISANT UN REGISTRE X86 */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande de registre x86. */ G_DEFINE_TYPE(GX86RegisterOperand, g_x86_register_operand, G_TYPE_X86_OPERAND); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des opérandes de registre x86. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_register_operand_class_init(GX86RegisterOperandClass *klass) { } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande de registre x86. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_register_operand_init(GX86RegisterOperand *operand) { GArchOperand *parent; /* Instance parente */ parent = G_ARCH_OPERAND(operand); parent->get_text = (get_operand_text_fc)g_x86_register_operand_get_text; } /****************************************************************************** * * * Paramètres : data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * size = taille de l'opérande, et donc du registre. * * base = indice du premier registre. * * * * Description : Crée un opérande visant un registre x86. * * * * Retour : Opérande mis en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_x86_register_operand_new_from_opcode(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size, bin_t base) { GX86RegisterOperand *result; /* Structure à retourner */ x86_register *reg; /* Registre lu */ reg = get_x86_register(size, data[*pos] - base); if (reg != NULL) { (*pos)++; result = g_object_new(G_TYPE_X86_REGISTER_OPERAND, NULL); result->reg = reg; } else result = NULL; return G_ARCH_OPERAND(result); } /****************************************************************************** * * * Paramètres : data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * size = taille de l'opérande, et donc du registre. * * first = indique la partie du ModR/M à traiter. * * * * Description : Crée un opérande visant un registre x86. * * * * Retour : Opérande mis en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_x86_register_operand_new_from_mod_rm(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size, bool first) { GX86RegisterOperand *result; /* Structure à retourner */ bin_t index; /* Registre lu */ x86_register *reg; /* Registre créé */ if (first) index = data[*pos] & 0x07; else index = (data[*pos] & 0x38) >> 3; reg = get_x86_register(size, index); if (reg != NULL) { (*pos)++; result = g_object_new(G_TYPE_X86_REGISTER_OPERAND, NULL); result->reg = reg; } else result = NULL; return G_ARCH_OPERAND(result); } /****************************************************************************** * * * Paramètres : index = indice du registre visé. * * size = taille de l'opérande, et donc du registre. * * * * Description : Crée un opérande visant un registre x86 donné. * * * * Retour : Opérande mis en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_x86_register_operand_new_from_index(bin_t index, AsmOperandSize size) { GX86RegisterOperand *result; /* Structure à retourner */ x86_register *reg; /* Registre lu */ reg = get_x86_register(size, index); if (reg != NULL) { result = g_object_new(G_TYPE_X86_REGISTER_OPERAND, NULL); result->reg = reg; } else result = NULL; return G_ARCH_OPERAND(result); } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * format = format du binaire manipulé. * * syntax = type de représentation demandée. * * * * Description : Traduit un opérande en version humainement lisible. * * * * Retour : Chaîne de caractères à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ static char *g_x86_register_operand_get_text(const GX86RegisterOperand *operand, const GExeFormat *format, AsmSyntax syntax) { char *result; /* Chaîne à retourner */ result = x86_register_as_text(operand->reg, syntax); return result; } /* ---------------------------------------------------------------------------------- */ /* OPERANDES COMPLEXES DE TYPE MOD/RM */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande x86 de type ModRM. */ G_DEFINE_TYPE(GX86ModRMOperand, g_x86_mod_rm_operand, G_TYPE_ARCH_OPERAND); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des opérandes x86 de type ModRM. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_mod_rm_operand_class_init(GX86ModRMOperandClass *klass) { } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande x86 de type ModRM. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_mod_rm_operand_init(GX86ModRMOperand *operand) { GArchOperand *parent; /* Instance parente */ parent = G_ARCH_OPERAND(operand); parent->get_text = (get_operand_text_fc)g_x86_mod_rm_operand_get_text; } /****************************************************************************** * * * Paramètres : data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * size = taille de l'opérande, et donc du registre. * * * * Description : Crée un opérande x86 de type ModRM. * * * * Retour : Opérande mis en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_x86_mod_rm_operand_new(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size) { GX86ModRMOperand *result; /* Structure à retourner */ uint8_t mod; /* Modificateur présent */ x86_register *reg; /* Registre lu */ mod = (data[*pos] & 0xc0); if (mod == 0xc0) return g_x86_register_operand_new_from_mod_rm(data, pos, len, size, true); reg = get_x86_register(size, data[*pos] & 0x07); if (reg == NULL) return NULL; (*pos)++; /* Vieille astuce de l'emplacement mémoire fixe ? */ if (is_x86_register_base_pointer(reg) && mod == 0x00) { free_x86_register(reg); return g_imm_operand_new_from_data(MDS_32_BITS/* FIXME */, data, pos, len, SRE_LITTLE); } result = g_object_new(G_TYPE_X86_MOD_RM_OPERAND, NULL); /* A la recherche d'un SIB */ if (is_x86_register_stack_pointer(reg)) { free_x86_register(reg); result->base = get_x86_register(size, data[*pos] & 0x07); if (result->base == NULL) goto gxmron_error; result->index = get_x86_register(size, (data[*pos] & 0x38) >> 3); if (result->index == NULL) goto gxmron_error; result->scale = ((data[*pos] & 0xc0) >> 6); if (is_x86_register_stack_pointer(result->index)) { free_x86_register(result->index); result->index = result->base; result->base = NULL; } (*pos)++; } else result->index = reg; /* Décallage supplémentaire ? */ switch (mod) { case 0x00: if (result->base != NULL && is_x86_register_base_pointer(result->base)) { free_x86_register(result->base); result->base = NULL; result->displacement = g_imm_operand_new_from_data(size/* FIXME : !convert mds/aos */, data, pos, len, SRE_LITTLE); if (result->displacement == NULL) goto gxmron_error; } break; case 0x40: result->displacement = g_imm_operand_new_from_data(MDS_8_BITS_SIGNED, data, pos, len, SRE_LITTLE); if (result->displacement == NULL) goto gxmron_error; break; case 0x80: result->displacement = g_imm_operand_new_from_data(MDS_32_BITS_SIGNED/* FIXME ! 16/32 */, data, pos, len, SRE_LITTLE); if (result->displacement == NULL) goto gxmron_error; break; } return G_ARCH_OPERAND(result); gxmron_error: /* FIXME free(result);*/ return NULL; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * format = format du binaire manipulé. * * syntax = type de représentation demandée. * * * * Description : Traduit un opérande en version humainement lisible. * * * * Retour : Chaîne de caractères à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ static char *g_x86_mod_rm_operand_get_text(const GX86ModRMOperand *operand, const GExeFormat *format, AsmSyntax syntax) { char *result; /* Chaîne à retourner */ char *tmp; /* Chaîne de registre */ switch (syntax) { case ASX_INTEL: result = (char *)calloc(1 + 10 + 2, sizeof(char)); strcpy(result, "["); if (operand->scale > 0) snprintf(&result[1], 12, "%d*", (int)pow(2, operand->scale)); tmp = x86_register_as_text(operand->index, syntax); result = stradd(result, tmp); free(tmp); if (operand->base != NULL) { result = stradd(result, "+"); tmp = x86_register_as_text(operand->base, syntax); result = stradd(result, tmp); free(tmp); } if (operand->displacement != NULL) { if (g_imm_operand_is_negative(operand->displacement)) result = stradd(result, "-"); else result = stradd(result, "+"); tmp = g_arch_operand_get_text(G_ARCH_OPERAND(operand->displacement), format, syntax); result = stradd(result, tmp); free(tmp); } result = stradd(result, "]"); break; case ASX_ATT: result = strdup("[modRM]"); break; } return result; } /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * scale = facteur sous forme de puissance de deux. [OUT * * index = register principal de l'opérande. [OUT] * * * * Description : Fournit l'indice et l'échelle d'un opérande x86 ModRM. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_x86_mod_rm_operand_get_scale_and_index(const GX86ModRMOperand *operand, uint8_t *scale, const x86_register **index) { *scale = operand->scale; *index = operand->index; } /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * * * Description : Fournit le registre de base d'un opérande x86 ModRM. * * * * Retour : Registre de base de l'opérande. * * * * Remarques : - * * * ******************************************************************************/ const x86_register *g_x86_mod_rm_operand_get_base(const GX86ModRMOperand *operand) { return operand->base; } /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * * * * Description : Fournit le décallage supplémentaire d'un opérande x86 ModRM. * * * * Retour : Décallage numérique pour l'opérande. * * * * Remarques : - * * * ******************************************************************************/ const GImmOperand *g_x86_mod_rm_operand_get_displacement(const GX86ModRMOperand *operand) { return operand->displacement; } /* ---------------------------------------------------------------------------------- */ /* OPERANDES D'ADRESSES RELATIVES */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande x86 d'adresse relative. */ G_DEFINE_TYPE(GX86RelativeOperand, g_x86_relative_operand, G_TYPE_X86_OPERAND); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des opérandes x86 d'adresse relative. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_relative_operand_class_init(GX86RelativeOperandClass *klass) { } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande x86 d'adresse relative. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_relative_operand_init(GX86RelativeOperand *operand) { GArchOperand *parent; /* Instance parente */ parent = G_ARCH_OPERAND(operand); parent->get_text = (get_operand_text_fc)g_x86_relative_operand_get_text; } /****************************************************************************** * * * Paramètres : data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * size = taille de l'opérande, et donc du registre. * * base = indice du premier registre. * * * * Description : Crée un opérande X86 d'adresse relative. * * * * Retour : Opérande mis en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_x86_relative_operand_new(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size, vmpa_t base) { GX86RelativeOperand *result; /* Structure à retourner */ off_t init_pos; /* Position avant lecture */ uint8_t val8; /* Valeur sur 8 bits */ uint16_t val16; /* Valeur sur 16 bits */ uint32_t val32; /* Valeur sur 32 bits */ uint32_t address32; /* Adresse finale visée */ init_pos = *pos; switch (size) { case AOS_8_BITS_UNSIGNED: read_u8(&val8, data, pos, len, SRE_LITTLE); address32 = val8; break; case AOS_16_BITS_UNSIGNED: read_u16(&val16, data, pos, len, SRE_LITTLE); address32 = val16; break; case AOS_32_BITS_UNSIGNED: read_u32(&val32, data, pos, len, SRE_LITTLE); address32 = val32; break; default: return NULL; break; } address32 += base + (*pos - init_pos); result = g_object_new(G_TYPE_X86_RELATIVE_OPERAND, NULL); result->immediate = g_imm_operand_new_from_value(AOS_32_BITS/*FIXME*/, address32); return G_ARCH_OPERAND(result); } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * format = format du binaire manipulé. * * syntax = type de représentation demandée. * * * * Description : Traduit un opérande en version humainement lisible. * * * * Retour : Chaîne de caractères à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ static char *g_x86_relative_operand_get_text(const GX86RelativeOperand *operand, const GExeFormat *format, AsmSyntax syntax) { char *result; /* Chaîne à retourner */ result = g_arch_operand_get_text(operand->immediate, format, syntax); return result; } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * * * Description : Fournit l'adresse relative représentée par une opérande X86. * * * * Retour : Valeur portée par l'opérande. * * * * Remarques : - * * * ******************************************************************************/ const GImmOperand *g_x86_relative_operand_get_value(const GX86RelativeOperand *operand) { return operand->immediate; } /* ---------------------------------------------------------------------------------- */ /* OPERANDES D'EMPLACEMENTS MEMOIRE */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande d'emplacement mémoire x86. */ G_DEFINE_TYPE(GX86MOffsOperand, g_x86_moffs_operand, G_TYPE_X86_OPERAND); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des opérandes d'emplacement mémoire x86.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_moffs_operand_class_init(GX86MOffsOperandClass *klass) { } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande d'emplacement mémoire x86.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_x86_moffs_operand_init(GX86MOffsOperand *operand) { GArchOperand *parent; /* Instance parente */ parent = G_ARCH_OPERAND(operand); parent->get_text = (get_operand_text_fc)g_x86_moffs_operand_get_text; } /****************************************************************************** * * * Paramètres : data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * size = taille de l'opérande, et donc du registre. * * * * Description : Crée un opérande d'emplacement mémoire x86. * * * * Retour : Opérande mis en place. * * * * Remarques : - * * * ******************************************************************************/ GArchOperand *g_x86_moffs_operand_new(const bin_t *data, off_t *pos, off_t len, AsmOperandSize size) { GX86MOffsOperand *result; /* Structure à retourner */ GImmOperand *offset; /* Emplacement lu */ result = NULL; offset = g_imm_operand_new_from_data(size/* FIXME : !convert mds/aos */, data, pos, len, SRE_LITTLE); if (offset != NULL) { result = g_object_new(G_TYPE_X86_MOFFS_OPERAND, NULL); result->offset = offset; } return G_ARCH_OPERAND(result); } /****************************************************************************** * * * Paramètres : operand = opérande à traiter. * * format = format du binaire manipulé. * * syntax = type de représentation demandée. * * * * Description : Traduit un opérande en version humainement lisible. * * * * Retour : Chaîne de caractères à libérer de la mémoire. * * * * Remarques : - * * * ******************************************************************************/ static char *g_x86_moffs_operand_get_text(const GX86MOffsOperand *operand, const GExeFormat *format, AsmSyntax syntax) { char *result; /* Chaîne à retourner */ result = g_arch_operand_get_text(operand->offset, format, syntax); result = strprep(result, "ds:"); return result; } /* ---------------------------------------------------------------------------------- */ /* AIDE A LA CREATION D'OPERANDES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : instr = instruction dont la définition est à compléter. [OUT]* * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * type = type de l'opérande. * * ... = éventuelle(s) information(s) complémentaire(s). * * * * Description : Procède à la lecture d'un opérande donné. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool x86_read_one_operand(GArchInstruction *instr, const bin_t *data, off_t *pos, off_t len, X86OperandType type, ...) { va_list ap; /* Liste des compléments */ AsmOperandSize oprsize; /* Taille des opérandes */ vmpa_t offset; /* Adresse courante */ bin_t base; /* Indice du premier registre */ GArchOperand *op; /* Opérande unique décodé */ va_start(ap, type); /* Lecture du premier opérande */ switch (type) { case X86_OTP_IMM8: op = g_imm_operand_new_from_data(MDS_8_BITS, data, pos, len, SRE_LITTLE); break; case X86_OTP_IMM1632: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op = g_imm_operand_new_from_data(oprsize == AOS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, pos, len, SRE_LITTLE); break; case X86_OTP_REL8: offset = va_arg(ap, vmpa_t); op = g_x86_relative_operand_new(data, pos, len, AOS_8_BITS, offset + 1); break; case X86_OTP_REL1632: oprsize = va_arg(ap, AsmOperandSize); offset = va_arg(ap, vmpa_t); op = g_x86_relative_operand_new(data, pos, len, oprsize, offset + 1); break; case X86_OTP_R8: op = g_x86_register_operand_new_from_mod_rm(data, pos, len, AOS_8_BITS, true); break; case X86_OTP_R1632: oprsize = va_arg(ap, AsmOperandSize); op = g_x86_register_operand_new_from_mod_rm(data, pos, len, oprsize, true); break; case X86_OTP_OP_R8: base = (bin_t)va_arg(ap, int); op = g_x86_register_operand_new_from_opcode(data, pos, len, AOS_8_BITS, base); break; case X86_OTP_OP_R1632: oprsize = va_arg(ap, AsmOperandSize); base = (bin_t)va_arg(ap, int); op = g_x86_register_operand_new_from_opcode(data, pos, len, oprsize, base); break; case X86_OTP_RM8: op = g_x86_mod_rm_operand_new(data, pos, len, AOS_8_BITS); break; case X86_OTP_RM1632: oprsize = va_arg(ap, AsmOperandSize); op = g_x86_mod_rm_operand_new(data, pos, len, oprsize); break; case X86_OTP_CL: op = g_x86_register_operand_new_from_index(0x01, AOS_8_BITS); break; case X86_OTP_AL: op = g_x86_register_operand_new_from_index(0x00, AOS_8_BITS); break; case X86_OTP_E_AX: oprsize = va_arg(ap, AsmOperandSize); op = g_x86_register_operand_new_from_index(0x00, oprsize); break; } va_end(ap); if (op == NULL) return false; g_arch_instruction_attach_one_operand(instr, op); return true; } /****************************************************************************** * * * Paramètres : instr = instruction dont la définition est à compléter. [OUT]* * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * type1 = type du premier opérande. * * type2 = type du second opérande. * * ... = éventuelle(s) information(s) complémentaire(s). * * * * Description : Procède à la lecture de deux opérandes donnés. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool x86_read_two_operands(GArchInstruction *instr, const bin_t *data, off_t *pos, off_t len, X86OperandType type1, X86OperandType type2, ...) { va_list ap; /* Liste des compléments */ AsmOperandSize oprsize; /* Taille des opérandes */ bool op1_first; /* Position de l'opérande #1 */ bool op2_first; /* Position de l'opérande #2 */ off_t op1_pos; /* Position après lecture #1 */ bin_t base; /* Indice du premier registre */ GArchOperand *op1; /* Premier opérande décodé */ off_t op2_pos; /* Position après lecture #2 */ GArchOperand *op2; /* Second opérande décodé */ va_start(ap, type2); oprsize = AOS_UNDEFINED; if (type1 & X86_OTP_RM_TYPE) { op1_first = true; op2_first = false; } else if (type2 & X86_OTP_RM_TYPE) { op1_first = false; op2_first = true; } else { op1_first = true; op2_first = false; } /* Lecture du premier opérande */ op1_pos = *pos; switch (type1) { case X86_OTP_IMM8: op1 = g_imm_operand_new_from_data(MDS_8_BITS, data, &op1_pos, len, SRE_LITTLE); break; case X86_OTP_IMM1632: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op1 = g_imm_operand_new_from_data(oprsize == AOS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, &op1_pos, len, SRE_LITTLE); break; case X86_OTP_MOFFS8: op1 = g_x86_moffs_operand_new(data, &op1_pos, len, AOS_8_BITS); break; case X86_OTP_MOFFS1632: oprsize = va_arg(ap, AsmOperandSize); op1 = g_x86_moffs_operand_new(data, &op1_pos, len, oprsize); break; case X86_OTP_R8: op1 = g_x86_register_operand_new_from_mod_rm(data, &op1_pos, len, AOS_8_BITS, op1_first); break; case X86_OTP_R1632: oprsize = va_arg(ap, AsmOperandSize); op1 = g_x86_register_operand_new_from_mod_rm(data, &op1_pos, len, oprsize, op1_first); break; case X86_OTP_OP_R8: base = (bin_t)va_arg(ap, int); op1 = g_x86_register_operand_new_from_opcode(data, &op1_pos, len, AOS_8_BITS, base); break; case X86_OTP_OP_R1632: oprsize = va_arg(ap, AsmOperandSize); base = (bin_t)va_arg(ap, int); op1 = g_x86_register_operand_new_from_opcode(data, &op1_pos, len, oprsize, base); break; case X86_OTP_RM8: op1 = g_x86_mod_rm_operand_new(data, &op1_pos, len, AOS_8_BITS); break; case X86_OTP_RM1632: oprsize = va_arg(ap, AsmOperandSize); op1 = g_x86_mod_rm_operand_new(data, &op1_pos, len, oprsize); break; case X86_OTP_CL: op1 = g_x86_register_operand_new_from_index(0x01, AOS_8_BITS); break; case X86_OTP_AL: op1 = g_x86_register_operand_new_from_index(0x00, AOS_8_BITS); break; case X86_OTP_E_AX: oprsize = va_arg(ap, AsmOperandSize); op1 = g_x86_register_operand_new_from_index(0x00, oprsize); break; } if (op1 == NULL) { va_end(ap); return false; } /* Lecture du second opérande */ if ((type1 & X86_OTP_REG_TYPE || type1 & X86_OTP_RM_TYPE) && (type2 & X86_OTP_IMM_TYPE)) op2_pos = op1_pos; else op2_pos = *pos; switch (type2) { case X86_OTP_IMM8: op2 = g_imm_operand_new_from_data(MDS_8_BITS, data, &op2_pos, len, SRE_LITTLE); break; case X86_OTP_IMM1632: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op2 = g_imm_operand_new_from_data(oprsize == AOS_32_BITS ? MDS_32_BITS : MDS_16_BITS, data, &op2_pos, len, SRE_LITTLE); break; case X86_OTP_MOFFS8: op2 = g_x86_moffs_operand_new(data, &op2_pos, len, AOS_8_BITS); break; case X86_OTP_MOFFS1632: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op2 = g_x86_moffs_operand_new(data, &op2_pos, len, oprsize); break; case X86_OTP_R8: op2 = g_x86_register_operand_new_from_mod_rm(data, &op2_pos, len, AOS_8_BITS, op2_first); break; case X86_OTP_R1632: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op2 = g_x86_register_operand_new_from_mod_rm(data, &op2_pos, len, oprsize, op2_first); break; case X86_OTP_RM8: op2 = g_x86_mod_rm_operand_new(data, &op2_pos, len, AOS_8_BITS); break; case X86_OTP_RM1632: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op2 = g_x86_mod_rm_operand_new(data, &op2_pos, len, oprsize); break; case X86_OTP_CL: op2 = g_x86_register_operand_new_from_index(0x01, AOS_8_BITS); break; case X86_OTP_AL: op2 = g_x86_register_operand_new_from_index(0x00, AOS_8_BITS); break; case X86_OTP_E_AX: if (oprsize == AOS_UNDEFINED) oprsize = va_arg(ap, AsmOperandSize); op2 = g_x86_register_operand_new_from_index(0x00, oprsize); break; } if (op2 == NULL) { free(op1); va_end(ap); return false; } va_end(ap); /* Assemblage final */ *pos = MAX(op1_pos, op2_pos); g_arch_instruction_attach_two_operands(instr, op1, op2); return true; }