/* 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;
operand->value.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->value.val8);
break;
case ASX_ATT:
snprintf(buffer, len, "$0x%02hhx", operand->value.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:
if ((len - *pos) < 1) return false;
break;
case AOS_16_BITS:
if ((len - *pos) < 2) return false;
break;
case AOS_32_BITS:
if ((len - *pos) < 4) return false;
break;
case AOS_64_BITS:
if ((len - *pos) < 8) return false;
break;
}
va_start(ap, len);
switch (size)
{
case AOS_8_BITS:
val8 = va_arg(ap, uint8_t *);
*val8 = data[*pos];
*pos += 1;
break;
case AOS_16_BITS:
val16 = va_arg(ap, uint16_t *);
*val16 = data[*pos] | (uint16_t)data[*pos + 1] << 8;
*pos += 2;
break;
case AOS_32_BITS:
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:
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. *
* 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)
{
/* Vérifications sanitaires */
switch (size)
{
case AOS_8_BITS:
if ((len - *pos) < 1) return false;
break;
case AOS_16_BITS:
if ((len - *pos) < 2) return false;
break;
case AOS_32_BITS:
if ((len - *pos) < 4) return false;
break;
case AOS_64_BITS:
if ((len - *pos) < 8) return false;
break;
}
operand->type = AOT_IMM;
operand->size = size;
switch (size)
{
case AOS_8_BITS:
operand->value.val8 = data[*pos];
*pos += 1;
break;
case AOS_16_BITS:
operand->value.val16 = data[*pos] | (uint16_t)data[*pos + 1] << 8;
*pos += 2;
break;
case AOS_32_BITS:
operand->value.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:
operand->value.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;
}
return true;
}
/******************************************************************************
* *
* 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 *val8; /* Valeur sur 8 bits */
const uint16_t *val16; /* Valeur sur 16 bits */
const uint32_t *val32; /* Valeur sur 32 bits */
const uint64_t *val64; /* Valeur sur 64 bits */
operand->type = AOT_IMM;
operand->size = size;
va_start(ap, size);
switch (size)
{
case AOS_8_BITS:
val8 = va_arg(ap, const uint8_t *);
operand->value.val8 = *val8;
break;
case AOS_16_BITS:
val16 = va_arg(ap, const uint16_t *);
operand->value.val16 = *val16;
break;
case AOS_32_BITS:
val32 = va_arg(ap, const uint32_t *);
operand->value.val32 = *val32;
break;
case AOS_64_BITS:
val64 = va_arg(ap, const uint64_t *);
operand->value.val64 = *val64;
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->value.val8 & 0x80)
{
val8 = operand->value.val8 - 1;
val8 = ~val8;
operand->value.val8 = ref + (*pos - old_pos);
operand->value.val8 -= val8;
}
else operand->value.val8 += ref + (*pos - old_pos);
break;
case AOS_16_BITS:
if (operand->value.val16 & 0x8000)
{
val16 = operand->value.val16 - 1;
val16 = ~val16;
operand->value.val16 = ref + (*pos - old_pos);
operand->value.val16 -= val16;
}
else operand->value.val16 += ref + (*pos - old_pos);
break;
case AOS_32_BITS:
if (operand->value.val32 & 0x80000000)
{
val32 = operand->value.val32 - 1;
val32 = ~val32;
operand->value.val32 = ref + (*pos - old_pos);
operand->value.val32 -= val32;
}
else operand->value.val32 += ref + (*pos - old_pos);
break;
case AOS_64_BITS:
if (operand->value.val64 & 0x8000000000000000ull)
{
val64 = operand->value.val64 - 1;
val64 = ~val64;
operand->value.val64 = ref + (*pos - old_pos);
operand->value.val64 -= val64;
}
else operand->value.val64 += ref + (*pos - old_pos);
break;
}
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:
snprintf(buffer, len, "0x%hhx", operand->value.val8);
break;
case AOS_16_BITS:
snprintf(buffer, len, "0x%hx", operand->value.val16);
break;
case AOS_32_BITS:
snprintf(buffer, len, "0x%x", operand->value.val32);
break;
case AOS_64_BITS:
snprintf(buffer, len, "0x%llx", operand->value.val64);
break;
}
break;
case ASX_ATT:
switch (operand->size)
{
case AOS_8_BITS:
snprintf(buffer, len, "$0x%hhx", operand->value.val8);
break;
case AOS_16_BITS:
snprintf(buffer, len, "$0x%hx", operand->value.val16);
break;
case AOS_32_BITS:
snprintf(buffer, len, "$0x%x", operand->value.val32);
break;
case AOS_64_BITS:
snprintf(buffer, len, "$0x%llx", operand->value.val64);
break;
}
break;
}
}