/* OpenIDA - Outil d'analyse de fichiers binaires
* operand.h - prototypes pour la gestion des operandes de l'architecture MIPS
*
* 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 "../immediate.h"
#include "../operand-int.h"
#include "../../common/endianness.h"
#include "../../common/extstr.h"
/* ------------------------ COQUILLE VIDE POUR OPERANDE MIPS ------------------------ */
/* Définition d'un opérande de la MIPS (instance) */
struct _GMipsOperand
{
GArchOperand parent; /* Instance parente */
};
/* Définition d'un opérande de la MIPS (classe) */
struct _GMipsOperandClass
{
GArchOperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes MIPS de base. */
static void g_mips_operand_class_init(GMipsOperandClass *);
/* Initialise une instance d'opérande de base pour MIPS. */
static void g_mips_operand_init(GMipsOperand *);
/* ----------------------- OPERANDES OFFRANT UN REGISTRE MIPS ----------------------- */
/* Définition d'un opérande visant un registre MIPS (instance) */
struct _GMipsRegisterOperand
{
GMipsOperand parent; /* Instance parente */
mips_register *reg; /* Registre représenté */
};
/* Définition d'un opérande visant un registre MIPS (classe) */
struct _GMipsRegisterOperandClass
{
GMipsOperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes de registre MIPS. */
static void g_mips_register_operand_class_init(GMipsRegisterOperandClass *);
/* Initialise une instance d'opérande de registre MIPS. */
static void g_mips_register_operand_init(GMipsRegisterOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_mips_register_operand_get_text(const GMipsRegisterOperand *, const GExeFormat *, AsmSyntax);
/* -------------------------- OPERANDES DE CONTENU MEMOIRE -------------------------- */
/* Définition d'un opérande MIPS pointeur un contenu mémoire (instance) */
struct _GMipsMemContentOperand
{
GMipsOperand parent; /* Instance parente */
mips_register *base; /* Base de la lecture */
GArchOperand *offset; /* Décallage à appliquer */
};
/* Définition d'un opérande MIPS pointeur un contenu mémoire (classe) */
struct _GMipsMemContentOperandClass
{
GMipsOperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes MIPS de contenu mémoire. */
static void g_mips_mem_content_operand_class_init(GMipsMemContentOperandClass *);
/* Initialise une instance d'opérande MIPS de contenu mémoire. */
static void g_mips_mem_content_operand_init(GMipsMemContentOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_mips_mem_content_operand_get_text(const GMipsMemContentOperand *, const GExeFormat *, AsmSyntax);
/* ----------------------------- OPERANDES DE DECALLAGE ----------------------------- */
/* Définition d'un opérande MIPS de décallage (instance) */
struct _GMipsOffsetOperand
{
GMipsOperand parent; /* Instance parente */
GArchOperand *offset; /* Décallage à appliquer */
};
/* Définition d'un opérande MIPS de décallage (classe) */
struct _GMipsOffsetOperandClass
{
GMipsOperandClass parent; /* Classe parente */
};
/* Initialise la classe des opérandes MIPS de décallage. */
static void g_mips_offset_operand_class_init(GMipsOffsetOperandClass *);
/* Initialise une instance d'opérande MIPS de décallage. */
static void g_mips_offset_operand_init(GMipsOffsetOperand *);
/* Traduit un opérande en version humainement lisible. */
static char *g_mips_offset_operand_get_text(const GMipsOffsetOperand *, const GExeFormat *, AsmSyntax);
/* ---------------------------------------------------------------------------------- */
/* COQUILLE VIDE POUR OPERANDE MIPS */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande de MIPS. */
G_DEFINE_TYPE(GMipsOperand, g_mips_operand, G_TYPE_ARCH_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes MIPS de base. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_operand_class_init(GMipsOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande de base pour MIPS. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_operand_init(GMipsOperand *operand)
{
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES OFFRANT UN REGISTRE MIPS */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande de registre MIPS. */
G_DEFINE_TYPE(GMipsRegisterOperand, g_mips_register_operand, G_TYPE_MIPS_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes de registre MIPS. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_register_operand_class_init(GMipsRegisterOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande de registre MIPS. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_register_operand_init(GMipsRegisterOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_mips_register_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : index = identifiant du registre à représenter. *
* *
* Description : Crée un opérande visant un registre MIPS. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_mips_register_operand_new(bin_t index)
{
GMipsRegisterOperand *result; /* Structure à retourner */
mips_register *reg; /* Registre lu */
reg = get_mips_register(index);
if (reg != NULL)
{
result = g_object_new(G_TYPE_MIPS_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_mips_register_operand_get_text(const GMipsRegisterOperand *operand, const GExeFormat *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
result = mips_register_as_text(operand->reg, syntax);
return result;
}
/******************************************************************************
* *
* Paramètres : operand = opérande à consulter. *
* *
* Description : Fournit le registre MIPS représenté. *
* *
* Retour : Régistre MIPS représenté. *
* *
* Remarques : - *
* *
******************************************************************************/
const mips_register *g_mips_register_operand_get_register(const GMipsRegisterOperand *operand)
{
return operand->reg;
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES DE CONTENU MEMOIRE */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande MIPS de contenu mémoire. */
G_DEFINE_TYPE(GMipsMemContentOperand, g_mips_mem_content_operand, G_TYPE_MIPS_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes MIPS de contenu mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_mem_content_operand_class_init(GMipsMemContentOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande MIPS de contenu mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_mem_content_operand_init(GMipsMemContentOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_mips_mem_content_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : index = indice du registre de base. *
* offset = décallage supplémentaire à appliquer. *
* *
* Description : Crée un opérande MIPS de contenu mémoire. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_mips_mem_content_operand_new(bin_t index, int16_t offset)
{
GMipsMemContentOperand *result; /* Structure à retourner */
mips_register *base; /* Registre lu */
base = get_mips_register(index);
if (base != NULL)
{
result = g_object_new(G_TYPE_MIPS_MEM_CONTENT_OPERAND, NULL);
result->base = base;
result->offset = g_imm_operand_new_from_value(MDS_16_BITS_SIGNED, offset);
}
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_mips_mem_content_operand_get_text(const GMipsMemContentOperand *operand, const GExeFormat *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
char *tmp; /* Déplacement */
result = mips_register_as_text(operand->base, syntax);
result = strprep(result, "[");
if (g_imm_operand_is_negative(operand->offset)) result = stradd(result, "-");
else result = stradd(result, "+");
tmp = g_arch_operand_get_text(G_ARCH_OPERAND(operand->offset), format, syntax);
result = stradd(result, tmp);
free(tmp);
result = stradd(result, "]");
return result;
}
/* ---------------------------------------------------------------------------------- */
/* OPERANDES DE DECALLAGE */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini par la GLib pour un opérande MIPS de décallage. */
G_DEFINE_TYPE(GMipsOffsetOperand, g_mips_offset_operand, G_TYPE_MIPS_OPERAND);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des opérandes MIPS de décallage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_offset_operand_class_init(GMipsOffsetOperandClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : operand = instance à initialiser. *
* *
* Description : Initialise une instance d'opérande MIPS de décallage. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_mips_offset_operand_init(GMipsOffsetOperand *operand)
{
GArchOperand *parent; /* Instance parente */
parent = G_ARCH_OPERAND(operand);
parent->get_text = (get_operand_text_fc)g_mips_offset_operand_get_text;
}
/******************************************************************************
* *
* Paramètres : offset = valeur de décallage à représenter. *
* *
* Description : Crée un opérande MIPS de décallage. *
* *
* Retour : Opérande mis en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_mips_offset_operand_new(int16_t offset)
{
GMipsOffsetOperand *result; /* Structure à retourner */
result = g_object_new(G_TYPE_MIPS_OFFSET_OPERAND, NULL);
result->offset = g_imm_operand_new_from_value(MDS_16_BITS_SIGNED, 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_mips_offset_operand_get_text(const GMipsOffsetOperand *operand, const GExeFormat *format, AsmSyntax syntax)
{
return g_arch_operand_get_text(G_ARCH_OPERAND(operand->offset), format, syntax);
}
/* ---------------------------------------------------------------------------------- */
/* 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. *
* count = type du premier opérande. *
* ... = type des opérandes à interpréter. *
* *
* 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 mips_read_n_operands(GArchInstruction *instr, const bin_t *data, off_t *pos, off_t len, unsigned int count, ...)
{
bool result; /* Statut à retourner */
uint32_t code; /* Code binaire à décoder */
MipsOperandType type; /* Type d'opérand interprétée */
va_list ap; /* Arguments potentiels */
unsigned int i; /* Boucle de parcours */
bin_t reg; /* Identifiant de registre */
GArchOperand *op; /* Opérande décodé */
if (!read_u32(&code, data, pos, len, SRE_LITTLE/* FIXME */))
return false;
result = true;
va_start(ap, count);
for (i = 0; i < count; i++)
{
type = va_arg(ap, MipsOperandType);
switch (type)
{
case MIPS_OTP_RS:
reg = (code & 0x3e00000) >> 21;
op = g_mips_register_operand_new(reg);
break;
case MIPS_OTP_RT:
reg = (code & 0x1f0000) >> 16;
op = g_mips_register_operand_new(reg);
break;
case MIPS_OTP_RD:
reg = (code & 0xf800) >> 11;
op = g_mips_register_operand_new(reg);
break;
case MIPS_OTP_IMMEDIATE:
op = g_imm_operand_new_from_value(MDS_16_BITS, code & 0xffff);
break;
case MIPS_OTP_MEM_CONTENT:
op = g_mips_mem_content_operand_new((code & 0x3e00000) >> 21, code & 0xffff);
break;
case MIPS_OTP_OFFSET:
op = g_mips_offset_operand_new(code & 0xffff);
break;
case MIPS_OTP_SA:
op = g_imm_operand_new_from_value(MDS_8_BITS, (code & 0x7c0) >> 6);
break;
default:
op = NULL;
break;
}
if (op == NULL) result = false;
else g_arch_instruction_attach_extra_operand(instr, op);
}
va_end(ap);
return result;
}