/* 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;
}
}