/* OpenIDA - Outil d'analyse de fichiers binaires * operand.c - gestion générique des opérandes * * 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 "operand-int.h" /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * value = valeur immédiate à renseigner. * * * * Description : Crée une opérande pour l'instruction 'db'. * * * * Retour : true si l'opérande a été définie avec succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool fill_db_operand(asm_operand *operand, uint8_t value) { operand->type = AOT_NONE; operand->size = AOS_8_BITS_UNSIGNED; operand->unsigned_imm.val8 = value; return true; } /****************************************************************************** * * * Paramètres : operand = instruction à traiter. * * buffer = tampon de sortie mis à disposition. [OUT] * * len = taille de ce tampon. * * syntax = type de représentation demandée. * * * * Description : Traduit une opérande de type 'db' en texte. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void print_db_operand(const asm_operand *operand, char *buffer, size_t len, AsmSyntax syntax) { switch (syntax) { case ASX_INTEL: snprintf(buffer, len, "0x%02hhx", operand->unsigned_imm.val8); break; case ASX_ATT: snprintf(buffer, len, "$0x%02hhx", operand->unsigned_imm.val8); break; } } /****************************************************************************** * * * Paramètres : size = taille de l'opérande souhaitée. * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * ... = adresse où placer la valeur lue. [OUT] * * * * Description : Lit une valeur (signée ou non) sur x bits. * * * * Retour : true si l'opération s'est effectuée avec succès, false sinon.* * * * Remarques : - * * * ******************************************************************************/ bool read_imm_value(AsmOperandSize size, const uint8_t *data, off_t *pos, off_t len, ...) { va_list ap; /* Récupération d'argument */ uint8_t *val8; /* Valeur sur 8 bits */ uint16_t *val16; /* Valeur sur 16 bits */ uint32_t *val32; /* Valeur sur 32 bits */ uint64_t *val64; /* Valeur sur 64 bits */ /* Vérifications sanitaires */ switch (size) { case AOS_8_BITS_UNSIGNED: case AOS_8_BITS_SIGNED: if ((len - *pos) < 1) return false; break; case AOS_16_BITS_UNSIGNED: case AOS_16_BITS_SIGNED: if ((len - *pos) < 2) return false; break; case AOS_32_BITS_UNSIGNED: case AOS_32_BITS_SIGNED: if ((len - *pos) < 4) return false; break; case AOS_64_BITS_UNSIGNED: case AOS_64_BITS_SIGNED: if ((len - *pos) < 8) return false; break; } va_start(ap, len); switch (size) { case AOS_8_BITS_UNSIGNED: case AOS_8_BITS_SIGNED: val8 = va_arg(ap, uint8_t *); *val8 = data[*pos]; *pos += 1; break; case AOS_16_BITS_UNSIGNED: case AOS_16_BITS_SIGNED: val16 = va_arg(ap, uint16_t *); *val16 = data[*pos] | (uint16_t)data[*pos + 1] << 8; *pos += 2; break; case AOS_32_BITS_UNSIGNED: case AOS_32_BITS_SIGNED: val32 = va_arg(ap, uint32_t *); *val32 = data[*pos] | (uint32_t)data[*pos + 1] << 8 | (uint32_t)data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24; *pos += 4; break; case AOS_64_BITS_UNSIGNED: case AOS_64_BITS_SIGNED: val64 = va_arg(ap, uint64_t *); *val64 = data[*pos] | (uint64_t)data[*pos + 1] << 8 | (uint64_t)data[*pos + 2] << 16 | (uint64_t)data[*pos + 3] << 24 | (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40 | (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56; *pos += 8; break; } va_end(ap); return true; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * * * Description : Indique le signe d'une valeur immédiate. * * * * Retour : true si la valeur est strictement négative, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool is_imm_operand_negative(const asm_operand *operand) { bool result; /* Bilan à renvoyer */ result = false; switch (operand->size) { case AOS_8_BITS_SIGNED: result = (operand->signed_imm.val8 & 0x80); break; case AOS_16_BITS_SIGNED: result = (operand->signed_imm.val16 & 0x8000); break; case AOS_32_BITS_SIGNED: result = (operand->signed_imm.val32 & 0x80000000); break; case AOS_64_BITS_SIGNED: result = (operand->signed_imm.val64 & 0x8000000000000000ll); break; default: /* Traitement non nécessaire */ break; } return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * size = taille de l'opérande souhaitée. * * * * Description : Précalcule une valeur humaine lisible d'une valeur signée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void cache_signed_imm_value(asm_operand *operand, AsmOperandSize size) { int8_t val8; /* Valeur sur 8 bits */ int16_t val16; /* Valeur sur 16 bits */ int32_t val32; /* Valeur sur 32 bits */ int64_t val64; /* Valeur sur 64 bits */ switch (size) { case AOS_8_BITS_SIGNED: if (operand->signed_imm.val8 & 0x80) { val8 = operand->signed_imm.val8 - 1; val8 = ~val8; operand->unsigned_imm.val8 = val8; } else operand->unsigned_imm.val8 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: if (operand->signed_imm.val16 & 0x8000) { val16 = operand->signed_imm.val16 - 1; val16 = ~val16; operand->unsigned_imm.val16 = val16; } else operand->unsigned_imm.val16 = operand->signed_imm.val16; break; case AOS_32_BITS_SIGNED: if (operand->signed_imm.val32 & 0x80000000) { val32 = operand->signed_imm.val32 - 1; val32 = ~val32; operand->unsigned_imm.val32 = val32; } else operand->unsigned_imm.val32 = operand->signed_imm.val32; break; case AOS_64_BITS_SIGNED: if (operand->signed_imm.val64 & 0x8000000000000000ll) { val64 = operand->signed_imm.val64 - 1; val64 = ~val64; operand->unsigned_imm.val64 = val64; } else operand->unsigned_imm.val64 = operand->signed_imm.val64; break; default: /* Traitement non nécessaire */ break; } } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * size = taille de l'opérande souhaitée. * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * * * Description : Crée une opérande contenant une valeur sur x bits. * * * * Retour : true si l'opération s'est effectuée avec succès, false sinon.* * * * Remarques : - * * * ******************************************************************************/ bool fill_imm_operand(asm_operand *operand, AsmOperandSize size, const uint8_t *data, off_t *pos, off_t len) { bool result; /* Bilan à retourner */ operand->type = AOT_IMM; operand->size = size; switch (size) { case AOS_8_BITS_UNSIGNED: result = read_imm_value(size, data, pos, len, &operand->unsigned_imm.val8); break; case AOS_16_BITS_UNSIGNED: result = read_imm_value(size, data, pos, len, &operand->unsigned_imm.val16); break; case AOS_32_BITS_UNSIGNED: result = read_imm_value(size, data, pos, len, &operand->unsigned_imm.val32); break; case AOS_64_BITS_UNSIGNED: result = read_imm_value(size, data, pos, len, &operand->unsigned_imm.val64); break; case AOS_8_BITS_SIGNED: result = read_imm_value(size, data, pos, len, &operand->signed_imm.val8); cache_signed_imm_value(operand, size); break; case AOS_16_BITS_SIGNED: result = read_imm_value(size, data, pos, len, &operand->signed_imm.val16); cache_signed_imm_value(operand, size); break; case AOS_32_BITS_SIGNED: result = read_imm_value(size, data, pos, len, &operand->signed_imm.val32); cache_signed_imm_value(operand, size); break; case AOS_64_BITS_SIGNED: result = read_imm_value(size, data, pos, len, &operand->signed_imm.val64); cache_signed_imm_value(operand, size); break; } return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * size = taille de l'opérande souhaitée. * * ... = valeur à utiliser. * * * * Description : Crée une opérande contenant une valeur sur x bits. * * * * Retour : true si l'opération s'est effectuée avec succès, false sinon.* * * * Remarques : - * * * ******************************************************************************/ bool fill_imm_operand_with_value(asm_operand *operand, AsmOperandSize size, ...) { va_list ap; /* Récupération d'argument */ const uint8_t *us_val8; /* Valeur sur 8 bits n.-s. */ const uint16_t *us_val16; /* Valeur sur 16 bits n.-s. */ const uint32_t *us_val32; /* Valeur sur 32 bits n.-s. */ const uint64_t *us_val64; /* Valeur sur 64 bits n.-s. */ const int8_t *s_val8; /* Valeur sur 8 bits signés */ const int16_t *s_val16; /* Valeur sur 16 bits signés */ const int32_t *s_val32; /* Valeur sur 32 bits signés */ const int64_t *s_val64; /* Valeur sur 64 bits signés */ operand->type = AOT_IMM; operand->size = size; va_start(ap, size); switch (size) { case AOS_8_BITS_UNSIGNED: us_val8 = va_arg(ap, const uint8_t *); operand->unsigned_imm.val8 = *us_val8; break; case AOS_16_BITS_UNSIGNED: us_val16 = va_arg(ap, const uint16_t *); operand->unsigned_imm.val16 = *us_val16; break; case AOS_32_BITS_UNSIGNED: us_val32 = va_arg(ap, const uint32_t *); operand->unsigned_imm.val32 = *us_val32; break; case AOS_64_BITS_UNSIGNED: us_val64 = va_arg(ap, const uint64_t *); operand->unsigned_imm.val64 = *us_val64; break; case AOS_8_BITS_SIGNED: s_val8 = va_arg(ap, const uint8_t *); operand->signed_imm.val8 = *s_val8; cache_signed_imm_value(operand, size); break; case AOS_16_BITS_SIGNED: s_val16 = va_arg(ap, const uint16_t *); operand->signed_imm.val16 = *s_val16; cache_signed_imm_value(operand, size); break; case AOS_32_BITS_SIGNED: s_val32 = va_arg(ap, const uint32_t *); operand->signed_imm.val32 = *s_val32; cache_signed_imm_value(operand, size); break; case AOS_64_BITS_SIGNED: s_val64 = va_arg(ap, const uint64_t *); operand->signed_imm.val64 = *s_val64; cache_signed_imm_value(operand, size); break; } va_end(ap); return true; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * size = taille de l'opérande souhaitée. * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * len = taille totale des données à analyser. * * ref = adresse de référence. * * * * Description : Crée une opérande contenant une valeur relative sur x bits. * * * * Retour : true si l'opération s'est effectuée avec succès, false sinon.* * * * Remarques : - * * * ******************************************************************************/ bool fill_relimm_operand(asm_operand *operand, AsmOperandSize size, const uint8_t *data, off_t *pos, off_t len, uint64_t ref) { bool result; /* Bilan à retourner */ off_t old_pos; /* Sauvegarde de l'évolution */ int8_t val8; /* Valeur sur 8 bits */ int16_t val16; /* Valeur sur 16 bits */ uint32_t val32; /* Valeur sur 32 bits */ int64_t val64; /* Valeur sur 64 bits */ old_pos = *pos; result = fill_imm_operand(operand, size, data, pos, len); if (result) switch (size) { case AOS_8_BITS: if (operand->unsigned_imm.val8 & 0x80) { val8 = operand->unsigned_imm.val8 - 1; val8 = ~val8; operand->unsigned_imm.val8 = ref + (*pos - old_pos); operand->unsigned_imm.val8 -= val8; } else operand->unsigned_imm.val8 += ref + (*pos - old_pos); break; case AOS_16_BITS: if (operand->unsigned_imm.val16 & 0x8000) { val16 = operand->unsigned_imm.val16 - 1; val16 = ~val16; operand->unsigned_imm.val16 = ref + (*pos - old_pos); operand->unsigned_imm.val16 -= val16; } else operand->unsigned_imm.val16 += ref + (*pos - old_pos); break; case AOS_32_BITS: if (operand->unsigned_imm.val32 & 0x80000000) { val32 = operand->unsigned_imm.val32 - 1; val32 = ~val32; operand->unsigned_imm.val32 = ref + (*pos - old_pos); operand->unsigned_imm.val32 -= val32; } else operand->unsigned_imm.val32 += ref + (*pos - old_pos); break; case AOS_64_BITS: if (operand->unsigned_imm.val64 & 0x8000000000000000ull) { val64 = operand->unsigned_imm.val64 - 1; val64 = ~val64; operand->unsigned_imm.val64 = ref + (*pos - old_pos); operand->unsigned_imm.val64 -= val64; } else operand->unsigned_imm.val64 += ref + (*pos - old_pos); break; } return result; } /****************************************************************************** * * * Paramètres : operand = structure dont le contenu est à définir. * * size = taille de l'opérande souhaitée. * * ... = zone d'enregistrement prévue. * * * * Description : Récupère la valeur d'une opérande sur x bits. * * * * Retour : true si l'opération s'est effectuée avec succès, false sinon.* * * * Remarques : - * * * ******************************************************************************/ bool get_imm_operand_value(asm_operand *operand, AsmOperandSize size, ...) { bool result; /* Bilan à retourner */ va_list ap; /* Récupération d'argument */ uint8_t *us_val8; /* Valeur sur 8 bits n.-s. */ uint16_t *us_val16; /* Valeur sur 16 bits n.-s. */ uint32_t *us_val32; /* Valeur sur 32 bits n.-s. */ uint64_t *us_val64; /* Valeur sur 64 bits n.-s. */ int8_t *s_val8; /* Valeur sur 8 bits signés */ int16_t *s_val16; /* Valeur sur 16 bits signés */ int32_t *s_val32; /* Valeur sur 32 bits signés */ int64_t *s_val64; /* Valeur sur 64 bits signés */ result = true; va_start(ap, size); switch (size) { case AOS_8_BITS_UNSIGNED: us_val8 = va_arg(ap, uint8_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *us_val8 = operand->unsigned_imm.val8; break; case AOS_8_BITS_SIGNED: *us_val8 = operand->signed_imm.val8; break; default: result = false; break; } break; case AOS_16_BITS_UNSIGNED: us_val16 = va_arg(ap, uint16_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *us_val16 = operand->unsigned_imm.val8; break; case AOS_16_BITS_UNSIGNED: *us_val16 = operand->unsigned_imm.val16; break; case AOS_8_BITS_SIGNED: *us_val16 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: *us_val16 = operand->signed_imm.val16; break; default: result = false; break; } break; case AOS_32_BITS_UNSIGNED: us_val32 = va_arg(ap, uint32_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *us_val32 = operand->unsigned_imm.val8; break; case AOS_16_BITS_UNSIGNED: *us_val32 = operand->unsigned_imm.val16; break; case AOS_32_BITS_UNSIGNED: *us_val32 = operand->unsigned_imm.val32; break; case AOS_8_BITS_SIGNED: *us_val32 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: *us_val32 = operand->signed_imm.val16; break; case AOS_32_BITS_SIGNED: *us_val32 = operand->signed_imm.val32; break; default: result = false; break; } break; case AOS_64_BITS_UNSIGNED: us_val64 = va_arg(ap, uint64_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *us_val64 = operand->unsigned_imm.val8; break; case AOS_16_BITS_UNSIGNED: *us_val64 = operand->unsigned_imm.val16; break; case AOS_32_BITS_UNSIGNED: *us_val64 = operand->unsigned_imm.val32; break; case AOS_64_BITS_UNSIGNED: *us_val64 = operand->unsigned_imm.val64; break; case AOS_8_BITS_SIGNED: *us_val64 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: *us_val64 = operand->signed_imm.val16; break; case AOS_32_BITS_SIGNED: *us_val64 = operand->signed_imm.val32; break; case AOS_64_BITS_SIGNED: *us_val64 = operand->signed_imm.val64; break; default: result = false; break; } break; case AOS_8_BITS_SIGNED: s_val8 = va_arg(ap, int8_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *s_val8 = operand->unsigned_imm.val8; break; case AOS_8_BITS_SIGNED: *s_val8 = operand->signed_imm.val8; break; default: result = false; break; } break; case AOS_16_BITS_SIGNED: s_val16 = va_arg(ap, int16_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *s_val16 = operand->unsigned_imm.val8; break; case AOS_16_BITS_UNSIGNED: *s_val16 = operand->unsigned_imm.val16; break; case AOS_8_BITS_SIGNED: *s_val16 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: *s_val16 = operand->signed_imm.val16; break; default: result = false; break; } break; case AOS_32_BITS_SIGNED: s_val32 = va_arg(ap, int32_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *s_val32 = operand->unsigned_imm.val8; break; case AOS_16_BITS_UNSIGNED: *s_val32 = operand->unsigned_imm.val16; break; case AOS_32_BITS_UNSIGNED: *s_val32 = operand->unsigned_imm.val32; break; case AOS_8_BITS_SIGNED: *s_val32 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: *s_val32 = operand->signed_imm.val16; break; case AOS_32_BITS_SIGNED: *s_val32 = operand->signed_imm.val32; break; default: result = false; break; } break; case AOS_64_BITS_SIGNED: s_val64 = va_arg(ap, int64_t *); switch (operand->size) { case AOS_8_BITS_UNSIGNED: *s_val64 = operand->unsigned_imm.val8; break; case AOS_16_BITS_UNSIGNED: *s_val64 = operand->unsigned_imm.val16; break; case AOS_32_BITS_UNSIGNED: *s_val64 = operand->unsigned_imm.val32; break; case AOS_64_BITS_UNSIGNED: *s_val64 = operand->unsigned_imm.val64; break; case AOS_8_BITS_SIGNED: *s_val64 = operand->signed_imm.val8; break; case AOS_16_BITS_SIGNED: *s_val64 = operand->signed_imm.val16; break; case AOS_32_BITS_SIGNED: *s_val64 = operand->signed_imm.val32; break; case AOS_64_BITS_SIGNED: *s_val64 = operand->signed_imm.val64; break; default: result = false; break; } break; default: result = false; break; } va_end(ap); return result; } /****************************************************************************** * * * Paramètres : operand = instruction à traiter. * * buffer = tampon de sortie mis à disposition. [OUT] * * len = taille de ce tampon. * * syntax = type de représentation demandée. * * * * Description : Traduit une opérande de valeur immédiate en texte. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void print_imm_operand(const asm_operand *operand, char *buffer, size_t len, AsmSyntax syntax) { switch (syntax) { case ASX_INTEL: switch (operand->size) { case AOS_8_BITS_UNSIGNED: case AOS_8_BITS_SIGNED: snprintf(buffer, len, "0x%hhx", operand->unsigned_imm.val8); break; case AOS_16_BITS_UNSIGNED: case AOS_16_BITS_SIGNED: snprintf(buffer, len, "0x%hx", operand->unsigned_imm.val16); break; case AOS_32_BITS_UNSIGNED: case AOS_32_BITS_SIGNED: snprintf(buffer, len, "0x%x", operand->unsigned_imm.val32); break; case AOS_64_BITS_UNSIGNED: case AOS_64_BITS_SIGNED: snprintf(buffer, len, "0x%llx", operand->unsigned_imm.val64); break; } break; case ASX_ATT: switch (operand->size) { case AOS_8_BITS_UNSIGNED: case AOS_8_BITS_SIGNED: snprintf(buffer, len, "$0x%hhx", operand->unsigned_imm.val8); break; case AOS_16_BITS_UNSIGNED: case AOS_16_BITS_SIGNED: snprintf(buffer, len, "$0x%hx", operand->unsigned_imm.val16); break; case AOS_32_BITS_UNSIGNED: case AOS_32_BITS_SIGNED: snprintf(buffer, len, "$0x%x", operand->unsigned_imm.val32); break; case AOS_64_BITS_UNSIGNED: case AOS_64_BITS_SIGNED: snprintf(buffer, len, "$0x%llx", operand->unsigned_imm.val64); break; } break; } } /* Initialise la classe générique des opérandes. */ static void g_arch_operand_class_init(GArchOperandClass *); /* Initialise une instance d'opérande d'architecture. */ static void g_arch_operand_init(GArchOperand *); /* Indique le type défini pour un opérande d'architecture. */ G_DEFINE_TYPE(GArchOperand, g_arch_operand, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe générique des opérandes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_class_init(GArchOperandClass *klass) { } /****************************************************************************** * * * Paramètres : operand = instance à initialiser. * * * * Description : Initialise une instance d'opérande d'architecture. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_arch_operand_init(GArchOperand *operand) { } /****************************************************************************** * * * 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 : - * * * ******************************************************************************/ char *g_arch_operand_get_text(const GArchOperand *operand, const exe_format *format, AsmSyntax syntax) { return operand->get_text(operand, format, syntax); }