/* Chrysalide - Outil d'analyse de fichiers binaires
* instruction.c - gestion générique des instructions
*
* Copyright (C) 2008-2020 Cyrille Bagard
*
* This file is part of Chrysalide.
*
* Chrysalide 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.
*
* Chrysalide 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 Chrysalide. If not, see .
*/
#include "instruction.h"
#include
#include
#include
#include
#include
#include
#include "instruction-int.h"
#include "storage.h"
#include "../analysis/storage/serialize-int.h"
#include "../core/columns.h"
#include "../core/logs.h"
#include "../core/processors.h"
#include "../glibext/gbinarycursor.h"
#include "../glibext/linegen-int.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 *);
/* Procède à l'initialisation de l'interface de génération. */
static void g_arch_instruction_generator_init(GLineGeneratorInterface *);
/* Procède à l'initialisation de l'interface de sérialisation. */
static void g_arch_instruction_serializable_init(GSerializableObjectInterface *);
/* Supprime toutes les références externes. */
static void g_arch_instruction_dispose(GArchInstruction *);
/* Procède à la libération totale de la mémoire. */
static void g_arch_instruction_finalize(GArchInstruction *);
/* Charge un contenu depuis une mémoire tampon. */
static bool g_arch_instruction_load_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
/* Sauvegarde toutes les destinations d'une instruction. */
bool g_arch_instruction_store_destinations(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
/* Indique le nombre de ligne prêtes à être générées. */
static size_t g_arch_instruction_count_lines(const GArchInstruction *);
#ifdef HAVE_GTK_SUPPORT
/* Retrouve l'emplacement correspondant à une position donnée. */
static void g_arch_instruction_compute_cursor(const GArchInstruction *, gint, size_t, size_t, GLineCursor **);
/* Détermine si le conteneur s'inscrit dans une plage donnée. */
static int g_arch_instruction_contain_cursor(const GArchInstruction *, size_t, size_t, const GLineCursor *);
#endif
/* Renseigne sur les propriétés liées à un générateur. */
static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *, size_t, size_t);
/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
static void _g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
/* Imprime dans une ligne de rendu le contenu représenté. */
static void g_arch_instruction_print(GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
/* -------------------- CONSERVATION ET RECHARGEMENT DES DONNEES -------------------- */
/* Charge un contenu depuis une mémoire tampon. */
static bool _g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
/* Charge un contenu depuis une mémoire tampon. */
static bool g_arch_instruction_load(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
/* Sauvegarde un contenu dans une mémoire tampon. */
static bool _g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
/* Sauvegarde un contenu dans une mémoire tampon. */
static bool g_arch_instruction_store(GArchInstruction *, GObjectStorage *, packed_buffer_t *);
/* Indique le type défini pour une instruction d'architecture. */
G_DEFINE_TYPE_WITH_CODE(GArchInstruction, g_arch_instruction, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_LINE_GENERATOR, g_arch_instruction_generator_init)
G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_arch_instruction_serializable_init));
/******************************************************************************
* *
* 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)
{
GObjectClass *object; /* Autre version de la classe */
GArchInstructionClass *instr; /* Encore une autre vision... */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_instruction_dispose;
object->finalize = (GObjectFinalizeFunc)g_arch_instruction_finalize;
instr = G_ARCH_INSTRUCTION_CLASS(klass);
instr->print = (print_instruction_fc)_g_arch_instruction_print;
instr->load = (load_instruction_fc)_g_arch_instruction_load;
instr->store = (store_instruction_fc)_g_arch_instruction_store;
}
/******************************************************************************
* *
* Paramètres : instr = instance à initialiser. *
* *
* Description : Initialise une instance d'instruction d'architecture. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_init(GArchInstruction *instr)
{
instr_extra_data_t *extra; /* Données insérées à modifier */
extra = GET_ARCH_INSTR_EXTRA(instr);
INIT_GOBJECT_EXTRA_LOCK(extra);
instr->operands = NULL;
instr->from = NULL;
instr->to = NULL;
}
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
* Description : Procède à l'initialisation de l'interface de génération. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_generator_init(GLineGeneratorInterface *iface)
{
iface->count = (linegen_count_lines_fc)g_arch_instruction_count_lines;
#ifdef HAVE_GTK_SUPPORT
iface->compute = (linegen_compute_fc)g_arch_instruction_compute_cursor;
iface->contain = (linegen_contain_fc)g_arch_instruction_contain_cursor;
#endif
iface->get_flags = (linegen_get_flags_fc)g_arch_instruction_get_flags2;
iface->print = (linegen_print_fc)g_arch_instruction_print;
}
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
* Description : Procède à l'initialisation de l'interface de sérialisation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_serializable_init(GSerializableObjectInterface *iface)
{
iface->load = (load_serializable_object_cb)g_arch_instruction_load;
iface->store = (store_serializable_object_cb)g_arch_instruction_store;
}
/******************************************************************************
* *
* Paramètres : instr = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_dispose(GArchInstruction *instr)
{
size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à manipuler */
g_arch_instruction_lock_operands(instr);
count = _g_arch_instruction_count_operands(instr);
for (i = 0; i < count; i++)
{
op = _g_arch_instruction_get_operand(instr, 0);
rem_item_from_flat_array(&instr->operands, 0, sizeof(GArchOperand *));
/**
* Une fois pour l'obtention, une autre pour la libération !
*/
g_object_unref(G_OBJECT(op));
g_object_unref(G_OBJECT(op));
}
g_arch_instruction_unlock_operands(instr);
#ifndef NDEBUG
g_arch_instruction_lock_src(instr);
assert(count_flat_array_items(instr->from) == 0);
g_arch_instruction_unlock_src(instr);
#endif
#ifndef NDEBUG
g_arch_instruction_lock_dest(instr);
assert(count_flat_array_items(instr->to) == 0);
g_arch_instruction_unlock_dest(instr);
#endif
G_OBJECT_CLASS(g_arch_instruction_parent_class)->dispose(G_OBJECT(instr));
}
/******************************************************************************
* *
* Paramètres : instr = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_finalize(GArchInstruction *instr)
{
G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr));
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
* *
* Description : Indique l'encodage d'une instruction de façon détaillée. *
* *
* Retour : Description humaine de l'encodage utilisé. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_arch_instruction_get_encoding(const GArchInstruction *instr)
{
return G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_encoding(instr);
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à modifier. *
* flag = drapeau d'information complémentaire à planter. *
* *
* Description : Ajoute une information complémentaire à une instruction. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag)
{
bool result; /* Bilan à retourner */
instr_extra_data_t *extra; /* Données insérées à modifier */
assert(flag <= AIF_HIGH_USER);
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = !(extra->flags & flag);
extra->flags |= flag;
UNLOCK_GOBJECT_EXTRA(extra);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à modifier. *
* flag = drapeau d'information complémentaire à planter. *
* *
* Description : Retire une information complémentaire à une instruction. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_unset_flag(GArchInstruction *instr, ArchInstrFlag flag)
{
bool result; /* Bilan à retourner */
instr_extra_data_t *extra; /* Données insérées à modifier */
assert(flag <= AIF_HIGH_USER);
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = (extra->flags & flag);
extra->flags &= ~flag;
UNLOCK_GOBJECT_EXTRA(extra);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
* flag = drapeau d'information à rechercher. *
* *
* Description : Détermine si une instruction possède un fanion particulier. *
* *
* Retour : Bilan de la détection. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag flag)
{
bool result; /* Bilan à retourner */
instr_extra_data_t *extra; /* Données insérées à modifier */
assert(flag <= AIF_HIGH_USER);
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = (extra->flags & flag);
UNLOCK_GOBJECT_EXTRA(extra);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à modifier. *
* *
* Description : Fournit les informations complémentaires d'une instruction. *
* *
* Retour : Eventuels drapeaux d'information complémentaire à plantés. *
* *
* Remarques : - *
* *
******************************************************************************/
ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
{
ArchInstrFlag result; /* Fanions à retourner */
instr_extra_data_t *extra; /* Données insérées à modifier */
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = extra->flags;
UNLOCK_GOBJECT_EXTRA(extra);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
* uid = identifiant unique par type d'instruction. *
* *
* Description : Définit l'identifiant unique pour un ensemble d'instructions.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_set_unique_id(GArchInstruction *instr, itid_t uid)
{
instr_extra_data_t *extra; /* Données insérées à modifier */
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
extra->uid = uid;
UNLOCK_GOBJECT_EXTRA(extra);
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
* *
* Description : Fournit l'identifiant unique pour un ensemble d'instructions.*
* *
* Retour : Identifiant unique par type d'instruction et architecture. *
* *
* Remarques : - *
* *
******************************************************************************/
itid_t g_arch_instruction_get_unique_id(const GArchInstruction *instr)
{
itid_t result; /* Numéro à retourner */
instr_extra_data_t *extra; /* Données insérées à consulter*/
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = extra->uid;
UNLOCK_GOBJECT_EXTRA(extra);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à traiter. *
* type = type de procédure à utiliser. *
* proc = représentation de l'architecture utilisée. *
* context = contexte associé à la phase de désassemblage. *
* format = accès aux données du binaire d'origine. *
* *
* Description : Complète un désassemblage accompli pour une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_call_hook(GArchInstruction *instr, InstrProcessHook type, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
{
GArchInstructionClass *class; /* Classe des instructions */
class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
if (class->call_hook != NULL)
class->call_hook(instr, type, proc, context, format);
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à modifier. *
* address = adresse virtuelle et/ou position physique. *
* length = taille de l'instruction. *
* *
* Description : Définit la localisation d'une instruction. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_set_range(GArchInstruction *instr, const mrange_t *range)
{
copy_mrange(&instr->range, range);
}
/******************************************************************************
* *
* Paramètres : instr = instruction quelconque à consulter. *
* *
* Description : Fournit la place mémoire d'une instruction. *
* *
* Retour : Zone mémoire couverte par l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
const mrange_t *g_arch_instruction_get_range(const GArchInstruction *instr)
{
return &instr->range;
}
/******************************************************************************
* *
* 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(const 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 = instruction à consulter. *
* rregs = liste des rgistres lus. [OUT] *
* rcount = nombre de registres lus. [OUT] *
* wregs = liste des rgistres écrits. [OUT] *
* wcount = nombre de registres écrits. [OUT] *
* *
* Description : Liste les registres lus et écrits par l'instruction. *
* *
* Retour : - *
* *
* Remarques : Les compteurs de références sont à décrémenter après usage ! *
* *
******************************************************************************/
void g_arch_instruction_get_rw_registers(const GArchInstruction *instr, GArchRegister ***rregs, size_t *rcount, GArchRegister ***wregs, size_t *wcount)
{
#if 0
size_t i; /* Boucle de parcours */
*rregs = NULL;
*rcount = 0;
*wregs = NULL;
*wcount = 0;
instr->get_rw_regs(instr, rregs, rcount, wregs, wcount);
for (i = 0; i < *rcount; i++)
g_object_ref(G_OBJECT((*rregs)[i]));
for (i = 0; i < *wcount; i++)
g_object_ref(G_OBJECT((*wregs)[i]));
#endif
}
/* ---------------------------------------------------------------------------------- */
/* MANIPULATION DES OPERANDES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : instr = instruction à mettre à jour. *
* *
* Description : Verrouille les accès à la liste des opérandes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_lock_operands(GArchInstruction *instr)
{
lock_flat_array(&instr->operands);
}
/******************************************************************************
* *
* Paramètres : instr = instruction à mettre à jour. *
* *
* Description : Déverrouille les accès à la liste des opérandes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_unlock_operands(GArchInstruction *instr)
{
unlock_flat_array(&instr->operands);
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* operand = 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)
{
GSingletonFactory *factory; /* Unise à instances uniques */
GArchOperand *singleton; /* Instance retenue */
factory = get_operands_factory();
singleton = G_ARCH_OPERAND(g_singleton_factory_get_instance(factory, G_SINGLETON_CANDIDATE(operand)));
g_object_unref(G_OBJECT(operand));
g_object_unref(G_OBJECT(factory));
g_arch_instruction_lock_operands(instr);
add_item_to_flat_array(&instr->operands, &singleton, sizeof(GArchOperand *));
g_arch_instruction_unlock_operands(instr);
}
/******************************************************************************
* *
* 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)
{
size_t result; /* Décompte à retourner */
result = count_flat_array_items(instr->operands);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instance à consulter. *
* index = indice de l'opérande concerné. *
* *
* Description : Fournit un opérande donné d'une instruction. *
* *
* Retour : Opérande trouvée. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *_g_arch_instruction_get_operand(const GArchInstruction *instr, size_t index)
{
GArchOperand *result; /* Opérande à retourner */
GArchOperand **ptr; /* Adresse dans le tableau */
ptr = get_flat_array_item(instr->operands, index, sizeof(GArchOperand *));
result = *ptr;
g_object_ref(G_OBJECT(result));
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* old = ancienne opérande à détacher. *
* new = nouvelle opérande à attacher. *
* *
* Description : Remplace un opérande d'une instruction par un autre. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _g_arch_instruction_replace_operand(GArchInstruction *instr, GArchOperand *old, GArchOperand *new)
{
bool result; /* Bilan à retourner */
size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à manipuler */
result = false;
count = _g_arch_instruction_count_operands(instr);
for (i = 0; i < count && !result; i++)
{
op = _g_arch_instruction_get_operand(instr, i);
result = (op == old);
g_object_unref(G_OBJECT(op));
}
if (result)
{
rpl_item_in_flat_array(instr->operands, i - 1, &new, sizeof(GArchOperand *));
g_object_unref(G_OBJECT(old));
}
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instance à mettre à jour. *
* target = instruction à venir dissocier. *
* *
* Description : Détache un opérande liée d'une instruction. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *target)
{
bool result; /* Bilan à retourner */
size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à manipuler */
result = false;
count = _g_arch_instruction_count_operands(instr);
for (i = 0; i < count && !result; i++)
{
op = _g_arch_instruction_get_operand(instr, i);
result = (op == target);
g_object_unref(G_OBJECT(op));
}
if (result)
{
rem_item_from_flat_array(&instr->operands, i - 1, sizeof(GArchOperand *));
g_object_unref(G_OBJECT(target));
}
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instance à consulter. *
* target = instruction à venir retrouver. *
* *
* Description : Détermine le chemin conduisant à un opérande. *
* *
* Retour : Chemin d'accès à l'opérande ou NULL en cas d'absence. *
* *
* Remarques : - *
* *
******************************************************************************/
char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target)
{
char *result; /* Chemin à retourner */
size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à manipuler */
int ret; /* Bilan d'une construction */
char *sub_path; /* Sous-chemin emprunté */
result = NULL;
g_arch_instruction_lock_operands(instr);
count = _g_arch_instruction_count_operands(instr);
/* Première passe : accès direct */
for (i = 0; i < count && result == NULL; i++)
{
op = _g_arch_instruction_get_operand(instr, i);
if (op == target)
{
ret = asprintf(&result, "%zu", i);
if (ret == -1)
{
LOG_ERROR_N("asprintf");
result = NULL;
}
}
g_object_unref(G_OBJECT(op));
}
/* Seconde passe : accès profond */
for (i = 0; i < count && result == NULL; i++)
{
op = _g_arch_instruction_get_operand(instr, i);
sub_path = g_arch_operand_find_inner_operand_path(op, target);
if (sub_path != NULL)
{
ret = asprintf(&result, "%zu:%s", i, sub_path);
if (ret == -1)
{
LOG_ERROR_N("asprintf");
result = NULL;
}
free(sub_path);
}
g_object_unref(G_OBJECT(op));
}
g_arch_instruction_unlock_operands(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instance à consulter. *
* path = chemin d'accès à un opérande à retrouver. *
* *
* Description : Obtient l'opérande correspondant à un chemin donné. *
* *
* Retour : Opérande trouvé ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path)
{
GArchOperand *result; /* Opérande trouvée à renvoyer */
size_t index; /* Indice de l'opérande visé */
char *end; /* Poursuite du parcours ? */
GArchOperand *found; /* Opérande trouvé */
result = NULL;
g_arch_instruction_lock_operands(instr);
/* Recherche au premier niveau */
index = strtoul(path, &end, 10);
if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL))
{
LOG_ERROR_N("strtoul");
goto done;
}
found = _g_arch_instruction_get_operand(instr, index);
if (found == NULL) goto done;
if (*end == '\0')
{
result = found;
goto done;
}
/* Recherche en profondeur */
assert(*end == ':');
result = g_arch_operand_get_inner_operand_from_path(found, end + 1);
g_object_unref(G_OBJECT(found));
done:
g_arch_instruction_unlock_operands(instr);
return result;
}
/* ---------------------------------------------------------------------------------- */
/* DEFINITION DES LIAISONS ENTRE INSTRUCTIONS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : instr = instruction à mettre à jour. *
* src = sélection de l'extrémité à traiter. *
* lock = indique le sens du verrouillage à mener. *
* *
* Description : Met à disposition un encadrement des accès aux liens. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_lock_unlock_links(GArchInstruction *instr, bool src, bool lock)
{
flat_array_t **array; /* Choix du tableau ciblé */
array = (src ? &instr->from : &instr->to);
if (lock)
lock_flat_array(array);
else
unlock_flat_array(array);
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* type = type de lien à détecter. *
* *
* Description : Détermine si un type de lien existe dans une instruction. *
* *
* Retour : Bilan du statut courant de l'instruction. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_has_link(GArchInstruction *instr, InstructionLinkType type)
{
bool result; /* Bilan à retourner */
size_t count; /* Nombre de liens à parcourir */
size_t i; /* Boucle de parcours */
const instr_link_t *dlink; /* Définition de destination */
result = false;
g_arch_instruction_lock_dest(instr);
count = g_arch_instruction_count_destinations(instr);
for (i = 0; i < count && !result; i++)
{
dlink = g_arch_instruction_get_destination(instr, i);
result = (dlink->type == type);
unref_instr_link(dlink);
}
g_arch_instruction_unlock_dest(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* dest = ligne visée par la liaison (côté destination). *
* *
* Description : Détermine si un lien est déjà établi entre deux instructions.*
* *
* Retour : Bilan de l'état actuel des liaisons. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_has_link_to(GArchInstruction *instr, const GArchInstruction *dest)
{
bool result; /* Bilan à retourner */
size_t count; /* Nombre de liens à parcourir */
size_t i; /* Boucle de parcours */
const instr_link_t *dlink; /* Définition de destination */
result = false;
g_arch_instruction_lock_dest(instr);
count = g_arch_instruction_count_destinations(instr);
for (i = 0; i < count && !result; i++)
{
dlink = g_arch_instruction_get_destination(instr, i);
result = (dlink->linked == dest);
unref_instr_link(dlink);
}
g_arch_instruction_unlock_dest(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* dest = ligne visée par la liaison (côté destination). *
* type = type de lien à construire. *
* *
* Description : Etablit un lien entre deux instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)
{
instr_link_t new_src; /* Nouveau lien à définir #1 */
instr_link_t new_dst; /* Nouveau lien à définir #2 */
/* Côté destination */
new_src.linked = instr;
new_src.type = type;
ref_instr_link((&new_src));
/* Côté point de départ */
new_dst.linked = dest;
new_dst.type = type;
ref_instr_link((&new_dst));
/* Ajout dans le respect d'une cohérence globale */
g_arch_instruction_lock_src(dest);
g_arch_instruction_lock_dest(instr);
add_item_to_flat_array(&dest->from, &new_src, sizeof(instr_link_t));
add_item_to_flat_array(&instr->to, &new_dst, sizeof(instr_link_t));
g_arch_instruction_unlock_dest(instr);
g_arch_instruction_unlock_src(dest);
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* dest = ligne visée par la liaison (côté destination). *
* old = ancien type de lien construit. *
* new = nouveau type de lien à construire. *
* *
* Description : Change la nature d'un lien entre deux instructions. *
* *
* Retour : true pour une mise à jour réussie, false sinon. *
* *
* Remarques : Le verrou doit être posé sur les destinations de 'instr'. *
* *
******************************************************************************/
bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType old, InstructionLinkType new)
{
bool result; /* Bilan à retourner */
size_t count; /* Raccourci pour la lecture */
size_t i; /* Boucle de parcours */
instr_link_t *slink; /* Définition de source */
instr_link_t *dlink; /* Définition de destination */
result = false;
/**
* Note : pour la récupération des liens de sources et de destinations,
* on n'utilise pas les fonctions g_arch_instruction_get_(source|destination)(),
* qui renvoient un pointeur non modifiable.
*
* On a en effet besoin de modifier le type de lien.
*/
g_arch_instruction_lock_src(dest);
/* Côté destination */
count = g_arch_instruction_count_sources(dest);
for (i = 0; i < count; i++)
{
slink = get_flat_array_item(dest->from, i, sizeof(instr_link_t));
if (slink->linked == instr && slink->type == old)
break;
}
if (i == count)
goto gaicl_exit;
/* Côté point de départ */
count = g_arch_instruction_count_destinations(instr);
for (i = 0; i < count; i++)
{
dlink = get_flat_array_item(instr->to, i, sizeof(instr_link_t));
if (dlink->linked == dest && dlink->type == old)
break;
}
if (i == count)
goto gaicl_exit;
/* Si les deux extrémités sont raccord... */
slink->type = new;
dlink->type = new;
result = true;
gaicl_exit:
g_arch_instruction_unlock_src(dest);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à traiter. *
* *
* Description : Supprime tous les liens établis avec d'autres instructions. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_arch_instruction_delete_all_links(GArchInstruction *instr)
{
instr_link_t *link_src; /* Lien à supprimer #2 */
GArchInstruction *other; /* Instruction de l'autre bout */
size_t count; /* Quantié de liens présents */
size_t i; /* Boucle de parcours */
instr_link_t *link_dst; /* Lien à supprimer #1 */
/* Coté sources */
g_arch_instruction_lock_src(instr);
while (count_flat_array_items(instr->from) > 0)
{
link_src = get_flat_array_item(instr->from, 0, sizeof(instr_link_t));
other = link_src->linked;
g_arch_instruction_lock_dest(other);
count = count_flat_array_items(other->to);
for (i = 0; i < count; i++)
{
link_dst = get_flat_array_item(other->to, i, sizeof(instr_link_t));
if (link_dst->linked == instr && link_dst->type == link_src->type)
{
unref_instr_link(link_dst);
rem_item_from_flat_array(&other->to, i, sizeof(instr_link_t));
break;
}
}
assert(i < count);
g_arch_instruction_unlock_dest(other);
unref_instr_link(link_src);
rem_item_from_flat_array(&instr->from, 0, sizeof(instr_link_t));
}
g_arch_instruction_unlock_src(instr);
/* Coté destinations */
g_arch_instruction_lock_dest(instr);
while (count_flat_array_items(instr->to) > 0)
{
link_dst = get_flat_array_item(instr->to, 0, sizeof(instr_link_t));
other = link_dst->linked;
g_arch_instruction_lock_src(other);
count = count_flat_array_items(other->from);
for (i = 0; i < count; i++)
{
link_src = get_flat_array_item(other->from, i, sizeof(instr_link_t));
if (link_src->linked == instr && link_src->type == link_dst->type)
{
unref_instr_link(link_src);
rem_item_from_flat_array(&other->from, i, sizeof(instr_link_t));
break;
}
}
assert(i < count);
g_arch_instruction_unlock_src(other);
unref_instr_link(link_dst);
rem_item_from_flat_array(&instr->to, 0, sizeof(instr_link_t));
}
g_arch_instruction_unlock_dest(instr);
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* *
* Description : Fournit la quantité d'instructions pointant vers une autre. *
* *
* Retour : Nombre de ces origines. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_arch_instruction_count_sources(const GArchInstruction *instr)
{
size_t result; /* Nombre de liens à renvoyer */
result = count_flat_array_items(instr->from);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* index = indice de l'élément à retrouver. *
* *
* Description : Fournit les détails d'une origine d'une instruction donnée. *
* *
* Retour : Lien déterminé vers une instruction d'origine. *
* *
* Remarques : - *
* *
******************************************************************************/
const instr_link_t *g_arch_instruction_get_source(GArchInstruction *instr, size_t index)
{
instr_link_t *result; /* Détails présents à renvoyer */
result = get_flat_array_item(instr->from, index, sizeof(instr_link_t));
ref_instr_link(result);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* count = quantié de liens présents. [OUT] *
* *
* Description : Fournit tous les détails d'origine d'une instruction donnée. *
* *
* Retour : Liens vers des instructions d'origine à libérer. *
* *
* Remarques : - *
* *
******************************************************************************/
instr_link_t *g_arch_instruction_get_sources(GArchInstruction *instr, size_t *count)
{
instr_link_t *result; /* Détails présents à renvoyer */
size_t i; /* Boucle de parcours */
const instr_link_t *link; /* Lien à fournir */
g_arch_instruction_lock_src(instr);
*count = g_arch_instruction_count_sources(instr);
if (*count == 0)
result = NULL;
else
{
result = (instr_link_t *)malloc(*count * sizeof(instr_link_t));
for (i = 0; i < *count; i++)
{
link = g_arch_instruction_get_source(instr, i);
memcpy(&result[i], link, sizeof(instr_link_t));
}
}
g_arch_instruction_unlock_src(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* *
* Description : Donne le nombre d'instructions non naturellement suivantes. *
* *
* Retour : Nombre de ces destinations. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_arch_instruction_count_destinations(const GArchInstruction *instr)
{
size_t result; /* Nombre de liens à renvoyer */
result = count_flat_array_items(instr->to);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* index = indice de l'élément à retrouver. *
* *
* Description : Fournit les détails d'une destination d'une instruction. *
* *
* Retour : Lien déterminé vers une instruction de destination. *
* *
* Remarques : - *
* *
******************************************************************************/
const instr_link_t *g_arch_instruction_get_destination(GArchInstruction *instr, size_t index)
{
instr_link_t *result; /* Détails présents à renvoyer */
result = get_flat_array_item(instr->to, index, sizeof(instr_link_t));
ref_instr_link(result);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* type = type de lien recherché. *
* *
* Description : Fournit la destination d'une instruction et d'un type donné. *
* *
* Retour : Instruction de destination trouvée ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GArchInstruction *g_arch_instruction_get_given_destination(GArchInstruction *instr, InstructionLinkType type)
{
GArchInstruction *result; /* Résultat à remonter */
size_t count; /* Nombre de liens à parcourir */
size_t i; /* Boucle de parcours */
const instr_link_t *dest; /* Destination à étudier */
result = NULL;
g_arch_instruction_lock_dest(instr);
count = g_arch_instruction_count_destinations(instr);
for (i = 0; i < count && result == NULL; i++)
{
dest = g_arch_instruction_get_destination(instr, i);
if (dest->type == type)
{
result = dest->linked;
g_object_ref(G_OBJECT(result));
}
unref_instr_link(dest);
}
g_arch_instruction_unlock_dest(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter. *
* count = quantié de liens présents. [OUT] *
* *
* Description : Fournit tous les détails de destination d'une instruction. *
* *
* Retour : Liens vers des instructions de destination à libérer. *
* *
* Remarques : - *
* *
******************************************************************************/
instr_link_t *g_arch_instruction_get_destinations(GArchInstruction *instr, size_t *count)
{
instr_link_t *result; /* Détails présents à renvoyer */
size_t i; /* Boucle de parcours */
const instr_link_t *link; /* Lien à fournir */
g_arch_instruction_lock_dest(instr);
*count = g_arch_instruction_count_destinations(instr);
if (*count == 0)
result = NULL;
else
{
result = (instr_link_t *)malloc(*count * sizeof(instr_link_t));
for (i = 0; i < *count; i++)
{
link = g_arch_instruction_get_destination(instr, i);
memcpy(&result[i], link, sizeof(instr_link_t));
}
}
g_arch_instruction_unlock_dest(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = élément GLib à constuire. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à lire. *
* *
* Description : Charge un contenu depuis une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_arch_instruction_load_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
uleb128_t count; /* Nombre de liens à charger */
uleb128_t i; /* Boucle de parcours */
GArchInstruction *linked; /* Lien vers une instruction */
uleb128_t type; /* Valeur ULEB128 à charger */
g_arch_instruction_lock_dest(instr);
result = unpack_uleb128(&count, pbuf);
for (i = 0; i < count && result; i++)
{
linked = G_ARCH_INSTRUCTION(g_object_storage_unpack_object(storage, "instructions", pbuf));
if (linked == NULL)
{
result = false;
break;
}
result = unpack_uleb128(&type, pbuf);
if (!result)
{
g_object_unref(G_OBJECT(linked));
break;
}
g_arch_instruction_link_with(instr, linked, type);
g_object_unref(G_OBJECT(linked));
}
g_arch_instruction_unlock_dest(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction dont les informations sont à consulter.*
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Sauvegarde toutes les destinations d'une instruction. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_arch_instruction_store_destinations(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
size_t count; /* Nombre d'éléments à traiter */
size_t kept; /* Nombre de liens conservés */
size_t i; /* Boucle de parcours */
const instr_link_t *link; /* Lien vers une instruction */
g_arch_instruction_lock_dest(instr);
count = g_arch_instruction_count_destinations(instr);
/**
* Le type de lien ILT_REF n'est mis en place que lors de la création
* d'opérandes de type G_TYPE_TARGET_OPERAND, et sera donc remis en place
* dynamiquement lors de la restauration de ces derniers.
*/
kept = 0;
for (i = 0; i < count; i++)
{
link = g_arch_instruction_get_destination(instr, i);
if (link->type != ILT_REF)
kept++;
unref_instr_link(link);
}
result = pack_uleb128((uleb128_t []){ kept }, pbuf);
for (i = 0; i < count && result; i++)
{
link = g_arch_instruction_get_destination(instr, i);
if (link->type != ILT_REF)
{
result = g_object_storage_pack_object(storage, "instructions",
G_SERIALIZABLE_OBJECT(link->linked), pbuf);
if (result)
result = pack_uleb128((uleb128_t []){ link->type }, pbuf);
}
unref_instr_link(link);
}
g_arch_instruction_unlock_dest(instr);
return result;
}
/* ---------------------------------------------------------------------------------- */
/* CONVERSIONS DU FORMAT DES INSTRUCTIONS */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à consulter. *
* *
* Description : Fournit le nom humain de l'instruction manipulée. *
* *
* Retour : Mot clef de bas niveau. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_arch_instruction_get_keyword(GArchInstruction *instr)
{
const char *result; /* Désignation à retourner */
result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_keyword(instr);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à consulter. *
* *
* Description : Construit un petit résumé concis de l'instruction. *
* *
* Retour : Chaîne de caractères à libérer après usage ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
char *g_arch_instruction_build_tooltip(const GArchInstruction *instr)
{
char *result; /* Description à retourner */
GArchInstructionClass *class; /* Classe des instructions */
class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
if (class->build_tooltip != NULL)
result = class->build_tooltip(instr);
else
result = NULL;
return result;
}
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à consulter. *
* *
* Description : Fournit une description pour l'instruction manipulée. *
* *
* Retour : Chaîne de caractères avec balises éventuelles. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_arch_instruction_get_description(const GArchInstruction *instr)
{
const char *result; /* Description à retourner */
result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->get_desc(instr);
return result;
}
/* ---------------------------------------------------------------------------------- */
/* OFFRE DE CAPACITES DE GENERATION */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : instr = générateur à consulter. *
* *
* Description : Indique le nombre de ligne prêtes à être générées. *
* *
* Retour : Nombre de lignes devant apparaître au final. *
* *
* Remarques : - *
* *
******************************************************************************/
static size_t g_arch_instruction_count_lines(const GArchInstruction *instr)
{
return 1;
}
#ifdef HAVE_GTK_SUPPORT
/******************************************************************************
* *
* Paramètres : instr = générateur à consulter. *
* x = position géographique sur la ligne concernée. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* cursor = emplacement à constituer. [OUT] *
* *
* Description : Retrouve l'emplacement correspondant à une position donnée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_compute_cursor(const GArchInstruction *instr, gint x, size_t index, size_t repeat, GLineCursor **cursor)
{
*cursor = g_binary_cursor_new();
g_binary_cursor_update(G_BINARY_CURSOR(*cursor), get_mrange_addr(&instr->range));
}
/******************************************************************************
* *
* Paramètres : instr = générateur à consulter. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* cursor = emplacement à analyser. *
* *
* Description : Détermine si le conteneur s'inscrit dans une plage donnée. *
* *
* Retour : Bilan de la détermination, utilisable en comparaisons. *
* *
* Remarques : - *
* *
******************************************************************************/
static int g_arch_instruction_contain_cursor(const GArchInstruction *instr, size_t index, size_t repeat, const GLineCursor *cursor)
{
int result; /* Conclusion à retourner */
vmpa2t addr; /* Autre emplacement à comparer*/
assert(G_IS_BINARY_CURSOR(cursor));
g_binary_cursor_retrieve(G_BINARY_CURSOR(cursor), &addr);
result = cmp_mrange_with_vmpa(&instr->range, &addr);
return result;
}
#endif
/******************************************************************************
* *
* Paramètres : instr = générateur à consulter. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* *
* Description : Renseigne sur les propriétés liées à un générateur. *
* *
* Retour : Propriétés particulières associées. *
* *
* Remarques : - *
* *
******************************************************************************/
static BufferLineFlags g_arch_instruction_get_flags2(const GArchInstruction *instr, size_t index, size_t repeat)
{
return BLF_HAS_CODE;
}
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à représenter. *
* line = ligne de rendu à compléter. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* content = éventuel contenu binaire brut à imprimer. *
* *
* Description : Ajoute à un tampon GLib le contenu de l'instance spécifiée. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void _g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
{
const char *key; /* Mot clef principal */
size_t klen; /* Taille de ce mot clef */
size_t count; /* Nombre d'opérandes en place */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à manipuler */
g_buffer_line_fill_phys(line, DLC_PHYSICAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range));
g_buffer_line_fill_virt(line, DLC_VIRTUAL, MDS_32_BITS_UNSIGNED, get_mrange_addr(&instr->range));
g_buffer_line_fill_content(line, DLC_BINARY, content, &instr->range, VMPA_NO_PHYSICAL);
/* Instruction proprement dite */
key = g_arch_instruction_get_keyword(instr);
klen = strlen(key);
g_buffer_line_append_text(line, DLC_ASSEMBLY_HEAD, key, klen, RTT_INSTRUCTION, G_OBJECT(instr));
/* Liste des opérandes */
g_arch_instruction_lock_operands(instr);
count = _g_arch_instruction_count_operands(instr);
if (count > 0)
{
op = _g_arch_instruction_get_operand(instr, 0);
g_arch_operand_print(op, line);
g_object_unref(G_OBJECT(op));
for (i = 1; i < count; i++)
{
g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL);
g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL);
op = _g_arch_instruction_get_operand(instr, i);
g_arch_operand_print(op, line);
g_object_unref(G_OBJECT(op));
}
}
g_arch_instruction_unlock_operands(instr);
}
/******************************************************************************
* *
* Paramètres : instr = générateur à utiliser pour l'impression. *
* line = ligne de rendu à compléter. *
* index = indice de cette même ligne dans le tampon global. *
* repeat = indice d'utilisations successives du générateur. *
* content = éventuel contenu binaire brut à imprimer. *
* *
* Description : Imprime dans une ligne de rendu le contenu représenté. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_arch_instruction_print(GArchInstruction *instr, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content)
{
G_ARCH_INSTRUCTION_GET_CLASS(instr)->print(instr, line, index, repeat, content);
}
/* ---------------------------------------------------------------------------------- */
/* CONSERVATION ET RECHARGEMENT DES DONNEES */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : instr = élément GLib à constuire. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à lire. *
* *
* Description : Charge un contenu depuis une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool _g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
instr_extra_data_t *extra; /* Données insérées à consulter*/
uleb128_t value; /* Valeur ULEB128 à charger */
uleb128_t count; /* Nombre d'éléments à traiter */
uleb128_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à traiter */
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = unpack_uleb128(&value, pbuf);
if (result)
extra->uid = value;
if (result)
{
result = unpack_uleb128(&value, pbuf);
if (result)
extra->flags = value;
}
UNLOCK_GOBJECT_EXTRA(extra);
if (result)
result = unpack_mrange(&instr->range, pbuf);
if (result)
{
result = unpack_uleb128(&count, pbuf);
for (i = 0; i < count && result; i++)
{
op = G_ARCH_OPERAND(g_object_storage_unpack_object(storage, "operands", pbuf));
result = (op != NULL);
if (result)
g_arch_instruction_attach_extra_operand(instr, op);
}
}
if (result)
result = g_arch_instruction_load_destinations(instr, storage, pbuf);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = élément GLib à constuire. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à lire. *
* *
* Description : Charge un contenu depuis une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_arch_instruction_load(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
GArchInstructionClass *class; /* Classe à activer */
class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
result = class->load(instr, storage, pbuf);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = élément GLib à consulter. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Sauvegarde un contenu dans une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool _g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
instr_extra_data_t *extra; /* Données insérées à consulter*/
size_t count; /* Nombre d'éléments à traiter */
size_t i; /* Boucle de parcours */
GArchOperand *op; /* Opérande à traiter */
extra = GET_ARCH_INSTR_EXTRA(instr);
LOCK_GOBJECT_EXTRA(extra);
result = pack_uleb128((uleb128_t []){ extra->uid }, pbuf);
if (result)
result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf);
UNLOCK_GOBJECT_EXTRA(extra);
if (result)
result = pack_mrange(&instr->range, pbuf);
if (result)
{
g_arch_instruction_lock_operands(instr);
count = _g_arch_instruction_count_operands(instr);
result = pack_uleb128((uleb128_t []){ count }, pbuf);
for (i = 0; i < count && result; i++)
{
op = _g_arch_instruction_get_operand(instr, i);
result = g_object_storage_pack_object(storage, "operands", G_SERIALIZABLE_OBJECT(op), pbuf);
g_object_unref(G_OBJECT(op));
}
g_arch_instruction_unlock_operands(instr);
}
if (result)
result = g_arch_instruction_store_destinations(instr, storage, pbuf);
return result;
}
/******************************************************************************
* *
* Paramètres : instr = élément GLib à consulter. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Sauvegarde un contenu dans une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_arch_instruction_store(GArchInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf)
{
bool result; /* Bilan à retourner */
GArchInstructionClass *class; /* Classe à activer */
class = G_ARCH_INSTRUCTION_GET_CLASS(instr);
result = class->store(instr, storage, pbuf);
return result;
}