/* OpenIDA - Outil d'analyse de fichiers binaires
* instruction.c - gestion générique des instructions
*
* 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 "instruction.h"
#include
#include "instruction-int.h"
#include "../common/extstr.h"
/* Initialise la classe générique des instructions. */
static void g_arch_instruction_class_init(GArchInstructionClass *);
/* Initialise une instance d'opérande d'architecture. */
static void g_arch_instruction_init(GArchInstruction *);
/* Ajoute du texte simple à un fichier ouvert en écriture. */
static void g_arch_instruction_add_text(const GArchInstruction *, GRenderingOptions *, MainRendering, FILE *);
/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
static void g_arch_instruction_to_buffer(const GArchInstruction *, GBufferLine *, GRenderingOptions *);
/* Indique le type défini pour une instruction d'architecture. */
G_DEFINE_TYPE(GArchInstruction, g_arch_instruction, G_TYPE_CONTENT_EXPORTER);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe générique des instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_class_init(GArchInstructionClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : instr = instance à initialiser. *
* *
* Description : Initialise une instance d'instruction d'architecture. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_init(GArchInstruction *instr)
{
GContentExporter *parent; /* Instance parente */
parent = G_CONTENT_EXPORTER(instr);
parent->add_text = (add_text_fc)g_arch_instruction_add_text;
parent->export_buffer = (export_buffer_fc)g_arch_instruction_to_buffer;
DL_LIST_ITEM_INIT(&instr->flow);
}
/******************************************************************************
* *
* Paramètres : instr = instruction à transcrire. *
* options = options de rendu. *
* rendering = support effectif final des lignes de code. *
* stream = flux ouvert en écriture. *
* *
* Description : Ajoute du texte simple à un fichier ouvert en écriture. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_add_text(const GArchInstruction *instr, GRenderingOptions *options, MainRendering rendering, FILE *stream)
{
GContentExporter *exporter; /* Autre vision de l'objet */
const char *key; /* Mot clef principal */
size_t klen; /* Taille de ce mot clef */
size_t i; /* Boucle de parcours */
exporter = G_CONTENT_EXPORTER(instr);
key = instr->get_text(instr,
g_rendering_options_get_format(options),
g_rendering_options_get_syntax(options));
klen = strlen(key);
g_content_exporter_insert_text(exporter, stream, key, klen, RTT_INSTRUCTION);
if (instr->operands_count > 0)
{
g_content_exporter_insert_text(exporter, stream, "\t", 1, RTT_NONE);
g_content_exporter_add_text(G_CONTENT_EXPORTER(G_ARCH_INSTRUCTION(instr)->operands[0]),
options, rendering, stream);
for (i = 1; i < instr->operands_count; i++)
{
g_content_exporter_insert_text(exporter, stream, ",", 1, RTT_NONE/* FIXME */);
g_content_exporter_insert_text(exporter, stream, " ", 1, RTT_NONE);
g_content_exporter_add_text(G_CONTENT_EXPORTER(G_ARCH_INSTRUCTION(instr)->operands[i]),
options, rendering, stream);
}
}
}
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à représenter. *
* buffer = espace où placer ledit contenu. *
* options = options de rendu. *
* *
* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_to_buffer(const GArchInstruction *instr, GBufferLine *buffer, GRenderingOptions *options)
{
GContentExporter *exporter; /* Autre vision de l'objet */
const char *key; /* Mot clef principal */
size_t klen; /* Taille de ce mot clef */
size_t i; /* Boucle de parcours */
exporter = G_CONTENT_EXPORTER(instr);
key = instr->get_text(instr,
g_rendering_options_get_format(options),
g_rendering_options_get_syntax(options));
klen = strlen(key);
g_content_exporter_insert_into_buffer(exporter, buffer, BLC_ASSEMBLY_HEAD,
key, klen, RTT_INSTRUCTION);
if (instr->operands_count > 0)
{
g_content_exporter_to_buffer(G_CONTENT_EXPORTER(G_ARCH_INSTRUCTION(instr)->operands[0]),
buffer, options);
for (i = 1; i < instr->operands_count; i++)
{
g_content_exporter_insert_into_buffer(exporter, buffer, BLC_ASSEMBLY,
",", 1, RTT_NONE/* FIXME */);
g_content_exporter_insert_into_buffer(exporter, buffer, BLC_ASSEMBLY,
" ", 1, RTT_NONE);
g_content_exporter_to_buffer(G_CONTENT_EXPORTER(G_ARCH_INSTRUCTION(instr)->operands[i]),
buffer, options);
}
}
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à modifier. *
* offset = position physique dans le code binaire. *
* length = taille de l'instruction. *
* address = adresse virtuelle ou position physique. *
* *
* Description : Définit la localisation d'une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_set_location(GArchInstruction *instr, off_t offset, off_t length, vmpa_t address)
{
instr->offset = offset;
instr->length = length;
instr->address = address;
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
* offset = position physique dans le code binaire/NULL. [OUT] *
* length = taille de l'instruction ou NULL. [OUT] *
* address = adresse virtuelle ou position physique/NULL. [OUT] *
* *
* Description : Fournit la localisation d'une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_get_location(GArchInstruction *instr, off_t *offset, off_t *length, vmpa_t *address)
{
if (offset != NULL) *offset = instr->offset;
if (length != NULL) *length = instr->length;
if (address != NULL) *address = instr->address;
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* opererand = instruction à venir associer. *
* *
* Description : Attache un opérande supplémentaire à une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_attach_extra_operand(GArchInstruction *instr, GArchOperand *operand)
{
instr->operands_count++;
instr->operands = (GArchOperand **)realloc(instr->operands, instr->operands_count * sizeof(GArchOperand *));
instr->operands[instr->operands_count - 1] = operand;
}
/******************************************************************************
* *
* Paramètres : instr = instance à consulter. *
* *
* Description : Indique la quantité d'opérandes présents dans l'instruction. *
* *
* Retour : Nombre d'opérandes attachés. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_arch_instruction_count_operands(const GArchInstruction *instr)
{
return instr->operands_count;
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* index = indice de l'opérande concernée. *
* *
* Description : Fournit un opérande donné d'une instruction. *
* *
* Retour : Opérande trouvée ou NULL si aucune. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index)
{
GArchOperand *result; /* Opérande à retourner */
if (index >= instr->operands_count) result = NULL;
else result = instr->operands[index];
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* new = nouvelle opérande à attacher. *
* old = ancienne opérande à détacher. *
* *
* Description : Remplace un opérande d'une instruction par un autre. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *new, const GArchOperand *old)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < instr->operands_count; i++)
if (instr->operands[i] == old)
break;
if (i < instr->operands_count)
instr->operands[i] = new;
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* opererand = instruction à venir dissocier. *
* *
* Description : Détache un opérande liée d'une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *operand)
{
size_t i; /* Boucle de parcours */
for (i = 0; i < instr->operands_count; i++)
if (instr->operands[i] == operand)
break;
if ((i + 1) < instr->operands_count)
memmove(&instr->operands[i], &instr->operands[i + 1],
(instr->operands_count - i - 1) * sizeof(GArchOperand *));
instr->operands_count--;
instr->operands = (GArchOperand **)realloc(instr->operands, instr->operands_count * sizeof(GArchOperand *));
}
/******************************************************************************
* *
* Paramètres : instr = instruction à traiter. *
* format = format du binaire manipulé. *
* syntax = type de représentation demandée. *
* *
* Description : Traduit une instruction en version humainement lisible. *
* *
* Retour : Chaîne de caractères à libérer de la mémoire. *
* *
* Remarques : - *
* *
******************************************************************************/
char *g_arch_instruction_get_text(const GArchInstruction *instr, const GExeFormat *format, AsmSyntax syntax)
{
char *result; /* Chaîne à retourner */
size_t i; /* Boucle de parcours */
char *opstr; /* Chaîne d'opérande */
return strdup("");
if (instr->operands_count == 0)
result = strdup(instr->get_text(instr, format, syntax));
else
{
result = g_arch_operand_get_text(G_ARCH_INSTRUCTION(instr)->operands[0], format, syntax);
for (i = 1; i < instr->operands_count; i++)
{
result = stradd(result, ", ");
opstr = g_arch_operand_get_text(G_ARCH_INSTRUCTION(instr)->operands[i], format, syntax);
result = stradd(result, opstr);
free(opstr);
}
result = strprep(result, "\t");
result = strprep(result, instr->get_text(instr, format, syntax));
}
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction à consulter. *
* addr = eventuelle adresse associée à faire connaître. [OUT] *
* *
* Description : Informe sur une éventuelle référence à une autre instruction.*
* *
* Retour : Type de lien trouvé ou ILT_NONE si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
InstructionLinkType g_arch_instruction_get_link(const GArchInstruction *instr, vmpa_t *addr)
{
return instr->get_link(instr, addr);
}
/******************************************************************************
* *
* Paramètres : instr = instruction à consulter. *
* *
* Description : Indique si l'instruction correspond à un retour de fonction. *
* *
* Retour : true si l'instruction est un 'return' quelconque ou false. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_is_return(const GArchInstruction *instr)
{
return instr->is_return(instr);
}
/******************************************************************************
* *
* Paramètres : instr = instruction d'origine à convertir. *
* ctx = contexte de la phase de décompilation. *
* *
* Description : Décompile une instruction de façon générique. *
* *
* Retour : Instruction mise en place ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GDecInstruction *g_arch_instruction_decompile(const GArchInstruction *instr, GDecContext *ctx)
{
GDecInstruction *result; /* Instruction à retourner */
if (instr->decomp != NULL)
result = instr->decomp(instr, ctx);
else
result = NULL;
return result;
}
/* ---------------------------------------------------------------------------------- */
/* TRAITEMENT DES INSTRUCTIONS PAR ENSEMBLE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : list = liste d'instructions à compléter, ou NULL. *
* instr = nouvelle instruction à intégrer à l'ensemble. *
* *
* Description : Ajoute une instruction à un ensemble existant. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_add_to_list(GArchInstruction **list, GArchInstruction *instr)
{
ainstr_list_add_tail(instr, list);
}
/******************************************************************************
* *
* Paramètres : list = liste d'instructions à consulter. *
* : iter = position actuelle dans la liste. *
* max = adresse marquant la limite (exclue) du parcours. *
* *
* Description : Fournit l'élement suivant un autre pour un parcours. *
* *
* Retour : Elément suivant ou NULL si aucun. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *g_arch_instruction_get_next_iter(GArchInstruction *list, const GArchInstruction *iter, vmpa_t max)
{
GArchInstruction *result; /* Elément suivant à renvoyer */
result = ainstr_list_next_iter(iter, list);
if (result != NULL && result->address >= max)
result = NULL;
return result;
}
/******************************************************************************
* *
* Paramètres : list = liste de lignes à parcourir. *
* addr = position en mémoire ou physique à chercher. *
* strict = définit la considération à porter à l'adresse. *
* *
* Description : Recherche une instruction d'après son adresse. *
* *
* Retour : Instruction trouvée à l'adresse donnée, NULL si aucune. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *g_arch_instruction_find_by_address(GArchInstruction *list, vmpa_t addr, bool strict)
{
GArchInstruction *result; /* Trouvaille à retourner */
ainstr_list_for_each(result, list)
{
if (strict && result->offset == addr) break;
else if (!strict && result->offset < addr
&& addr < (result->offset + result->length)) break;
}
return result;
}