summaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/Makefile.am1
-rw-r--r--src/arch/immediate.c107
-rw-r--r--src/arch/immediate.h12
-rw-r--r--src/arch/instruction-int.h9
-rw-r--r--src/arch/instruction.c335
-rw-r--r--src/arch/instruction.h17
-rw-r--r--src/arch/operand-int.h9
-rw-r--r--src/arch/operand.c200
-rw-r--r--src/arch/operand.h29
-rw-r--r--src/arch/post.c2
-rw-r--r--src/arch/raw.c121
-rw-r--r--src/arch/register.c79
-rw-r--r--src/arch/register.h24
-rw-r--r--src/arch/storage.c1593
-rw-r--r--src/arch/storage.h104
-rw-r--r--src/arch/target.c104
-rw-r--r--src/arch/target.h13
-rw-r--r--src/arch/undefined.c95
-rw-r--r--src/arch/undefined.h12
-rw-r--r--src/arch/vmpa.c58
-rw-r--r--src/arch/vmpa.h10
21 files changed, 2887 insertions, 47 deletions
diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am
index a5cde8f..c9cc63b 100644
--- a/src/arch/Makefile.am
+++ b/src/arch/Makefile.am
@@ -18,6 +18,7 @@ libarch_la_SOURCES = \
raw.h raw.c \
register-int.h \
register.h register.c \
+ storage.h storage.c \
target.h target.c \
undefined.h undefined.c \
vmpa.h vmpa.c
diff --git a/src/arch/immediate.c b/src/arch/immediate.c
index bf4a36a..1c084ea 100644
--- a/src/arch/immediate.c
+++ b/src/arch/immediate.c
@@ -109,6 +109,17 @@ static char *g_imm_operand_build_tooltip(const GImmOperand *, const GLoadedBinar
+/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
+
+
+/* Charge un opérande depuis une mémoire tampon. */
+static bool g_imm_operand_unserialize(GImmOperand *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde un opérande dans une mémoire tampon. */
+static bool g_imm_operand_serialize(const GImmOperand *, GAsmStorage *, packed_buffer *);
+
+
+
/* Indique le type défini pour un opérande de valeur numérique. */
G_DEFINE_TYPE(GImmOperand, g_imm_operand, G_TYPE_ARCH_OPERAND);
@@ -141,6 +152,9 @@ static void g_imm_operand_class_init(GImmOperandClass *klass)
operand->print = (operand_print_fc)g_imm_operand_print;
operand->build_tooltip = (operand_build_tooltip_fc)g_imm_operand_build_tooltip;
+ operand->unserialize = (unserialize_operand_fc)g_imm_operand_unserialize;
+ operand->serialize = (serialize_operand_fc)g_imm_operand_serialize;
+
}
@@ -1357,3 +1371,96 @@ bool g_imm_operand_to_off_t(const GImmOperand *operand, off_t *value, bool *nega
return false;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* TRANSPOSITIONS VIA CACHE DES OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à constituer. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge un opérande depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_imm_operand_unserialize(GImmOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchOperandClass *parent; /* Classe parente à consulter */
+
+ parent = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class);
+
+ result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &operand->raw, sizeof(uint64_t), true);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &operand->size, sizeof(MemoryDataSize), true);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &operand->def_display, sizeof(ImmOperandDisplay), true);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &operand->display, sizeof(ImmOperandDisplay), true);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &operand->misc, sizeof(uint8_t), false);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde un opérande dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_imm_operand_serialize(const GImmOperand *operand, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchOperandClass *parent; /* Classe parente à consulter */
+
+ parent = G_ARCH_OPERAND_CLASS(g_imm_operand_parent_class);
+
+ result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &operand->raw, sizeof(uint64_t), true);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &operand->size, sizeof(MemoryDataSize), true);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &operand->def_display, sizeof(ImmOperandDisplay), true);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &operand->display, sizeof(ImmOperandDisplay), true);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &operand->misc, sizeof(uint8_t), false);
+
+ return result;
+
+}
diff --git a/src/arch/immediate.h b/src/arch/immediate.h
index 2a7f015..8f8f097 100644
--- a/src/arch/immediate.h
+++ b/src/arch/immediate.h
@@ -53,12 +53,12 @@ typedef enum _ImmOperandDisplay
#define IOD_LAST_VALID IOD_CHAR
-#define G_TYPE_IMM_OPERAND g_imm_operand_get_type()
-#define G_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_imm_operand_get_type(), GImmOperand))
-#define G_IS_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_imm_operand_get_type()))
-#define G_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_IMM_OPERAND, GImmOperandClass))
-#define G_IS_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_IMM_OPERAND))
-#define G_IMM_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_IMM_OPERAND, GImmOperandClass))
+#define G_TYPE_IMM_OPERAND g_imm_operand_get_type()
+#define G_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_IMM_OPERAND, GImmOperand))
+#define G_IS_IMM_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_IMM_OPERAND))
+#define G_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_IMM_OPERAND, GImmOperandClass))
+#define G_IS_IMM_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_IMM_OPERAND))
+#define G_IMM_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_IMM_OPERAND, GImmOperandClass))
/* Définition d'un opérande de valeur numérique (instance) */
diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h
index 2adeed0..365c7e9 100644
--- a/src/arch/instruction-int.h
+++ b/src/arch/instruction-int.h
@@ -46,6 +46,12 @@ typedef char * (* build_instruction_tooltip_fc) (const GArchInstruction *);
/* Fournit une description pour l'instruction manipulée. */
typedef const char * (* get_instruction_desc_fc) (const GArchInstruction *);
+/* Charge une instruction depuis une mémoire tampon. */
+typedef bool (* unserialize_instruction_fc) (GArchInstruction *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde une instruction dans une mémoire tampon. */
+typedef bool (* serialize_instruction_fc) (GArchInstruction *, GAsmStorage *, packed_buffer *);
+
/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
typedef GBufferLine * (* print_instruction_fc) (const GArchInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
@@ -106,6 +112,9 @@ struct _GArchInstructionClass
build_instruction_tooltip_fc build_tooltip; /* Construction d'une bulle*/
get_instruction_desc_fc get_desc; /* Description assez complète */
+ unserialize_instruction_fc unserialize; /* Chargement depuis un tampon */
+ serialize_instruction_fc serialize; /* Conservation dans un tampon */
+
print_instruction_fc print; /* Imprime l'ensemble */
//get_instruction_rw_regs_fc get_rw_regs; /* Liste des registres liés */
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index be7ff37..e2d8d2a 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -30,6 +30,7 @@
#include "instruction-int.h"
+#include "storage.h"
#include "../glibext/linegen-int.h"
@@ -51,6 +52,17 @@ static void g_arch_instruction_finalize(GArchInstruction *);
+/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */
+
+
+/* Charge une instruction depuis une mémoire tampon. */
+static bool g_arch_instruction_unserialize(GArchInstruction *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde une instruction dans une mémoire tampon. */
+static bool g_arch_instruction_serialize(GArchInstruction *, GAsmStorage *, packed_buffer *);
+
+
+
/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
@@ -103,6 +115,9 @@ static void g_arch_instruction_class_init(GArchInstructionClass *klass)
instr = G_ARCH_INSTRUCTION_CLASS(klass);
+ instr->unserialize = (unserialize_instruction_fc)g_arch_instruction_unserialize;
+ instr->serialize = (serialize_instruction_fc)g_arch_instruction_serialize;
+
instr->print = (print_instruction_fc)_g_arch_instruction_print;
}
@@ -1055,7 +1070,7 @@ char *g_arch_instruction_build_tooltip(const GArchInstruction *instr)
* Remarques : - *
* *
******************************************************************************/
-
+
const char *g_arch_instruction_get_description(const GArchInstruction *instr)
{
const char *result; /* Description à retourner */
@@ -1069,6 +1084,324 @@ const char *g_arch_instruction_get_description(const GArchInstruction *instr)
/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge une instruction depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_arch_instruction_unserialize(GArchInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ packed_buffer op_pbuf; /* Tampon des données à écrire */
+ size_t count; /* Nombre d'éléments à traiter */
+ size_t i; /* Boucle de parcours */
+ off64_t pos; /* Position dans le flux */
+ GArchOperand *op; /* Opérande à traiter */
+ instr_link_t link; /* Lien vers une instruction */
+ packed_buffer ins_pbuf; /* Tampon des données à écrire */
+
+ result = unpack_mrange(&instr->range, pbuf);
+
+ if (result)
+ {
+ init_packed_buffer(&op_pbuf);
+
+ result = extract_packed_buffer(pbuf, &count, sizeof(size_t), true);
+
+ for (i = 0; i < count && result; i++)
+ {
+ result = extract_packed_buffer(pbuf, &pos, sizeof(off64_t), true);
+
+ if (result)
+ result = g_asm_storage_load_operand_data(storage, &op_pbuf, pos);
+
+ if (result)
+ {
+ op = g_arch_operand_load(storage, format, &op_pbuf);
+ result = (op != NULL);
+ }
+
+ if (result)
+ g_arch_instruction_attach_extra_operand(instr, op);
+
+ }
+
+ exit_packed_buffer(&op_pbuf);
+
+ }
+
+ bool unserialize_link(instr_link_t *lk)
+ {
+ bool status; /* Bilan d'une conservation */
+ phys_t lk_phys; /* Position physique courante */
+
+ status = extract_packed_buffer(pbuf, &lk_phys, sizeof(phys_t), true);
+
+ if (status)
+ {
+ lk->linked = g_asm_storage_get_instruction_at(storage, format, lk_phys, &ins_pbuf);
+ status = (lk->linked != NULL);
+ }
+
+ if (status)
+ {
+ status = extract_packed_buffer(pbuf, &lk->type, sizeof(InstructionLinkType), true);
+
+ if (!status)
+ g_object_unref(G_OBJECT(lk->linked));
+
+ }
+
+ return status;
+
+ }
+
+ if (result)
+ {
+ init_packed_buffer(&ins_pbuf);
+
+ result = extract_packed_buffer(pbuf, &count, sizeof(size_t), true);
+
+ for (i = 0; i < count && result; i++)
+ {
+ result = unserialize_link(&link);
+
+ if (result)
+ {
+ g_arch_instruction_link_with(instr, link.linked, link.type);
+ g_object_unref(G_OBJECT(link.linked));
+ }
+
+ }
+
+ exit_packed_buffer(&ins_pbuf);
+
+ }
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &instr->uid, sizeof(itid_t), true);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &instr->flags, sizeof(ArchInstrFlag), true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge une instruction depuis une mémoire tampon. *
+* *
+* Retour : Instruction d'assemblage constitué ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GArchInstruction *g_arch_instruction_load(GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ GArchInstruction *result; /* Instance à retourner */
+ bool status; /* Bilan du chargement */
+
+ result = G_ARCH_INSTRUCTION(g_asm_storage_create_object(storage, pbuf));
+
+ if (result != NULL)
+ {
+ status = G_ARCH_INSTRUCTION_GET_CLASS(result)->unserialize(result, storage, format, pbuf);
+
+ if (!status)
+ {
+ g_object_unref(G_OBJECT(result));
+ result = NULL;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde une instruction dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_arch_instruction_serialize(GArchInstruction *instr, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ packed_buffer op_pbuf; /* Tampon des données à écrire */
+ size_t count; /* Nombre d'éléments à traiter */
+ size_t i; /* Boucle de parcours */
+ GArchOperand *op; /* Opérande à traiter */
+ off64_t pos; /* Position dans le flux */
+ size_t kept; /* Nombre de liens conservés */
+ instr_link_t *link; /* Lien vers une instruction */
+
+ result = pack_mrange(&instr->range, pbuf);
+
+ if (result)
+ {
+ init_packed_buffer(&op_pbuf);
+
+ g_arch_instruction_lock_operands(instr);
+
+ count = _g_arch_instruction_count_operands(instr);
+
+ result = extend_packed_buffer(pbuf, &count, sizeof(size_t), true);
+
+ for (i = 0; i < count && result; i++)
+ {
+ op = _g_arch_instruction_get_operand(instr, i);
+
+ result = g_arch_operand_store(op, storage, &op_pbuf);
+
+ if (result)
+ result = g_asm_storage_store_operand_data(storage, &op_pbuf, &pos);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &pos, sizeof(off64_t), true);
+
+ g_object_unref(G_OBJECT(op));
+
+ }
+
+ g_arch_instruction_unlock_operands(instr);
+
+ exit_packed_buffer(&op_pbuf);
+
+ }
+
+ bool serialize_link(const instr_link_t *lk)
+ {
+ bool status; /* Bilan d'une conservation */
+ const mrange_t *range; /* Emplacement d'une instruct° */
+ phys_t lk_phys; /* Position physique courante */
+
+ if (lk->type == ILT_REF)
+ status = true;
+
+ else
+ {
+ range = g_arch_instruction_get_range(lk->linked);
+
+ lk_phys = get_phy_addr(get_mrange_addr(range));
+
+ status = extend_packed_buffer(pbuf, &lk_phys, sizeof(phys_t), true);
+
+ if (status)
+ status = extend_packed_buffer(pbuf, &lk->type, sizeof(InstructionLinkType), true);
+
+ }
+
+ return status;
+
+ }
+
+ if (result)
+ {
+ 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 && result; i++)
+ {
+ link = g_arch_instruction_get_destination(instr, i);
+
+ if (link->type != ILT_REF)
+ kept++;
+
+ }
+
+ result = extend_packed_buffer(pbuf, &kept, sizeof(size_t), true);
+
+ for (i = 0; i < count && result; i++)
+ {
+ link = g_arch_instruction_get_destination(instr, i);
+ result = serialize_link(link);
+ }
+
+ g_arch_instruction_unlock_dest(instr);
+
+ }
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &instr->uid, sizeof(itid_t), true);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &instr->flags, sizeof(ArchInstrFlag), true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde une instruction dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_arch_instruction_store(GArchInstruction *instr, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_asm_storage_store_object_gtype(storage, G_OBJECT(instr), pbuf);
+
+ if (result)
+ result = G_ARCH_INSTRUCTION_GET_CLASS(instr)->serialize(instr, storage, pbuf);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
/* OFFRE DE CAPACITES DE GENERATION */
/* ---------------------------------------------------------------------------------- */
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index 497b7f6..2201dd5 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -32,8 +32,8 @@
#include "immediate.h"
#include "register.h"
#include "vmpa.h"
-#include "../analysis/content.h"
#include "../analysis/type.h"
+#include "../common/packed.h"
#include "../format/executable.h"
@@ -260,4 +260,19 @@ const char *g_arch_instruction_get_description(const GArchInstruction *);
+/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */
+
+
+/* Depuis "storage.h" : définition d'une conservation d'instructions d'assemblage (instance) */
+typedef struct _GAsmStorage GAsmStorage;
+
+
+/* Charge une instruction depuis une mémoire tampon. */
+GArchInstruction *g_arch_instruction_load(GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde une instruction dans une mémoire tampon. */
+bool g_arch_instruction_store(GArchInstruction *, GAsmStorage *, packed_buffer *);
+
+
+
#endif /* _ARCH_INSTRUCTION_H */
diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h
index ac8d07c..c052e0a 100644
--- a/src/arch/operand-int.h
+++ b/src/arch/operand-int.h
@@ -38,6 +38,12 @@ typedef void (* operand_print_fc) (const GArchOperand *, GBufferLine *, AsmSynta
/* Construit un petit résumé concis de l'opérande. */
typedef char * (* operand_build_tooltip_fc) (const GArchOperand *, const GLoadedBinary *);
+/* Charge un opérande depuis une mémoire tampon. */
+typedef bool (* unserialize_operand_fc) (GArchOperand *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde un opérande dans une mémoire tampon. */
+typedef bool (* serialize_operand_fc) (const GArchOperand *, GAsmStorage *, packed_buffer *);
+
/* Adjonction de rendu alternatif */
typedef struct _alt_rendering
@@ -67,6 +73,9 @@ struct _GArchOperandClass
operand_print_fc print; /* Texte humain équivalent */
operand_build_tooltip_fc build_tooltip; /* Construction de description */
+ unserialize_operand_fc unserialize; /* Chargement depuis un tampon */
+ serialize_operand_fc serialize; /* Conservation dans un tampon */
+
};
diff --git a/src/arch/operand.c b/src/arch/operand.c
index 930a588..1d4b468 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -30,7 +30,9 @@
#include "operand-int.h"
+#include "storage.h"
#include "../common/sort.h"
+#include "../core/logs.h"
@@ -48,6 +50,17 @@ static void g_arch_operand_finalize(GArchOperand *);
+/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
+
+
+/* Charge un opérande depuis une mémoire tampon. */
+static bool g_arch_operand_unserialize(GArchOperand *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde un opérande dans une mémoire tampon. */
+static bool g_arch_operand_serialize(const GArchOperand *, GAsmStorage *, packed_buffer *);
+
+
+
/* Indique le type défini pour un opérande d'architecture. */
G_DEFINE_TYPE(GArchOperand, g_arch_operand, G_TYPE_OBJECT);
@@ -68,12 +81,18 @@ G_DEFINE_TYPE(GArchOperand, g_arch_operand, G_TYPE_OBJECT);
static void g_arch_operand_class_init(GArchOperandClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GArchOperandClass *operand; /* Encore une autre vision... */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_arch_operand_dispose;
object->finalize = (GObjectFinalizeFunc)g_arch_operand_finalize;
+ operand = G_ARCH_OPERAND_CLASS(klass);
+
+ operand->unserialize = (unserialize_operand_fc)g_arch_operand_unserialize;
+ operand->serialize = (serialize_operand_fc)g_arch_operand_serialize;
+
}
@@ -197,10 +216,17 @@ void g_arch_operand_set_alt_text(GArchOperand *operand, const char *text, Render
{
alt_len = strlen(text);
- operand->alt_info = (alt_rendering *)malloc(sizeof(RenderingTagType) + alt_len + 1);
+ if (alt_len == 0)
+ operand->alt_info = NULL;
+
+ else
+ {
+ operand->alt_info = (alt_rendering *)malloc(sizeof(RenderingTagType) + alt_len + 1);
+
+ operand->alt_info->tag = tag;
+ strcpy(operand->alt_info->text, text);
- operand->alt_info->tag = tag;
- strcpy(operand->alt_info->text, text);
+ }
}
@@ -270,3 +296,171 @@ char *g_arch_operand_build_tooltip(const GArchOperand *operand, const GLoadedBin
return result;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* TRANSPOSITIONS VIA CACHE DES OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à constituer. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge un opérande depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_arch_operand_unserialize(GArchOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ unsigned char len; /* Taille du contenu alternatif*/
+ char *text; /* Texte alternatif */
+ RenderingTagType tag; /* Type de rendu */
+
+ result = extract_packed_buffer(pbuf, &len, sizeof(unsigned char), false);
+
+ if (result && len > 0)
+ {
+ text = (char *)malloc(len);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, text, len, false);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &tag, sizeof(RenderingTagType), true);
+
+ if (result)
+ g_arch_operand_set_alt_text(operand, text, tag);
+
+ free(text);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge un opérande depuis une mémoire tampon. *
+* *
+* Retour : Opérande d'assemblage constitué ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GArchOperand *g_arch_operand_load(GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ GArchOperand *result; /* Instance à retourner */
+ bool status; /* Bilan du chargement */
+
+ result = G_ARCH_OPERAND(g_asm_storage_create_object(storage, pbuf));
+
+ if (result != NULL)
+ {
+ status = G_ARCH_OPERAND_GET_CLASS(result)->unserialize(result, storage, format, pbuf);
+
+ if (!status)
+ {
+ g_object_unref(G_OBJECT(result));
+ result = NULL;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde un opérande dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_arch_operand_serialize(const GArchOperand *operand, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ size_t len; /* Taille du contenu alternatif*/
+
+ if (operand->alt_info == NULL)
+ result = extend_packed_buffer(pbuf, (unsigned char []) { 0 }, sizeof(unsigned char), false);
+
+ else
+ {
+ len = strlen(operand->alt_info->text) + 1;
+ assert(len > 1);
+
+ if (len > (2 << (sizeof(unsigned char) * 8 - 1)))
+ {
+ log_variadic_message(LMT_ERROR, "Alternative text too long: '%s' (%zu bytes)",
+ operand->alt_info->text, len);
+ result = false;
+ }
+
+ else
+ result = extend_packed_buffer(pbuf, (unsigned char []) { len }, sizeof(unsigned char), false);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, operand->alt_info->text, len, false);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &operand->alt_info->tag, sizeof(RenderingTagType), true);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde un opérande dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_arch_operand_store(const GArchOperand *operand, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+
+ result = g_asm_storage_store_object_gtype(storage, G_OBJECT(operand), pbuf);
+
+ if (result)
+ result = G_ARCH_OPERAND_GET_CLASS(operand)->serialize(operand, storage, pbuf);
+
+ return result;
+
+}
diff --git a/src/arch/operand.h b/src/arch/operand.h
index cd140ba..bb7388d 100644
--- a/src/arch/operand.h
+++ b/src/arch/operand.h
@@ -28,6 +28,8 @@
#include <glib-object.h>
+#include "../common/packed.h"
+#include "../format/format.h"
#include "../glibext/gbufferline.h"
@@ -36,12 +38,12 @@
typedef struct _GLoadedBinary GLoadedBinary;
-#define G_TYPE_ARCH_OPERAND g_arch_operand_get_type()
-#define G_ARCH_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_operand_get_type(), GArchOperand))
-#define G_IS_ARCH_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_operand_get_type()))
-#define G_ARCH_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_OPERAND, GArchOperandClass))
-#define G_IS_ARCH_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_OPERAND))
-#define G_ARCH_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_OPERAND, GArchOperandClass))
+#define G_TYPE_ARCH_OPERAND g_arch_operand_get_type()
+#define G_ARCH_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_OPERAND, GArchOperand))
+#define G_IS_ARCH_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_OPERAND))
+#define G_ARCH_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_OPERAND, GArchOperandClass))
+#define G_IS_ARCH_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_OPERAND))
+#define G_ARCH_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_OPERAND, GArchOperandClass))
/* Définition générique d'un opérande d'architecture (instance) */
@@ -68,4 +70,19 @@ char *g_arch_operand_build_tooltip(const GArchOperand *, const GLoadedBinary *);
+/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
+
+
+/* Depuis "storage.h" : définition d'une conservation d'instructions d'assemblage (instance) */
+typedef struct _GAsmStorage GAsmStorage;
+
+
+/* Charge un opérande depuis une mémoire tampon. */
+GArchOperand *g_arch_operand_load(GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde un opérande dans une mémoire tampon. */
+bool g_arch_operand_store(const GArchOperand *, GAsmStorage *, packed_buffer *);
+
+
+
#endif /* _ARCH_OPERAND_H */
diff --git a/src/arch/post.c b/src/arch/post.c
index 5687556..de07499 100644
--- a/src/arch/post.c
+++ b/src/arch/post.c
@@ -54,10 +54,10 @@ void post_process_target_resolution(GArchInstruction *instr, GArchProcessor *pro
{
GArchOperand *op; /* Opérande numérique en place */
virt_t addr; /* Adresse visée par le saut */
+ vmpa2t target; /* Emplacement de la cible */
GBinFormat *bfmt; /* Version basique du format */
MemoryDataSize ptr_size; /* Taille de l'espace mémoire */
GTargetOperand *new; /* Instruction de ciblage */
- vmpa2t target; /* Emplacement de la cible */
mrange_t trange; /* Etendue du symbole à créer */
VMPA_BUFFER(loc); /* Conversion en chaîne */
char name[5 + VMPA_MAX_LEN]; /* Etiquette de la destination */
diff --git a/src/arch/raw.c b/src/arch/raw.c
index 36bb4b3..4ae1e11 100644
--- a/src/arch/raw.c
+++ b/src/arch/raw.c
@@ -77,6 +77,22 @@ static const char *g_raw_instruction_get_encoding(const GRawInstruction *);
/* Fournit le nom humain de l'instruction manipulée. */
static const char *g_raw_instruction_get_keyword(const GRawInstruction *, AsmSyntax);
+
+
+/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */
+
+
+/* Charge une instruction depuis une mémoire tampon. */
+static bool g_raw_instruction_unserialize(GRawInstruction *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde une instruction dans une mémoire tampon. */
+static bool g_raw_instruction_serialize(GRawInstruction *, GAsmStorage *, packed_buffer *);
+
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
static void g_raw_instruction_print(GRawInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
@@ -117,6 +133,10 @@ static void g_raw_instruction_class_init(GRawInstructionClass *klass)
instr->get_encoding = (get_instruction_encoding_fc)g_raw_instruction_get_encoding;
instr->get_keyword = (get_instruction_keyword_fc)g_raw_instruction_get_keyword;
+
+ instr->unserialize = (unserialize_instruction_fc)g_raw_instruction_unserialize;
+ instr->serialize = (serialize_instruction_fc)g_raw_instruction_serialize;
+
instr->print = (print_instruction_fc)g_raw_instruction_print;
}
@@ -475,6 +495,107 @@ static const char *g_raw_instruction_get_keyword(const GRawInstruction *instr, A
}
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge une instruction depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_raw_instruction_unserialize(GRawInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchInstructionClass *parent; /* Classe parente à consulter */
+ uint8_t boolean; /* Valeur booléenne */
+
+ parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class);
+
+ result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf);
+
+ if (result)
+ {
+ result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
+
+ if (result)
+ instr->is_padding = (boolean == 1 ? true : false);
+
+ }
+
+ if (result)
+ {
+ result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
+
+ if (result)
+ instr->is_string = (boolean == 1 ? true : false);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde une instruction dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_raw_instruction_serialize(GRawInstruction *instr, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchInstructionClass *parent; /* Classe parente à consulter */
+ uint8_t boolean; /* Valeur booléenne */
+
+ parent = G_ARCH_INSTRUCTION_CLASS(g_raw_instruction_parent_class);
+
+ result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf);
+
+ if (result)
+ {
+ boolean = (instr->is_padding ? 1 : 0);
+ result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
+ }
+
+ if (result)
+ {
+ boolean = (instr->is_string ? 1 : 0);
+ result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false);
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* OFFRE DE CAPACITES DE GENERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à représenter. *
diff --git a/src/arch/register.c b/src/arch/register.c
index 0033071..7e1bcc2 100644
--- a/src/arch/register.c
+++ b/src/arch/register.c
@@ -67,6 +67,17 @@ static void g_register_operand_print(const GRegisterOperand *, GBufferLine *, As
+/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
+
+
+/* Charge un opérande depuis une mémoire tampon. */
+static bool g_register_operand_unserialize(GRegisterOperand *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde un opérande dans une mémoire tampon. */
+static bool g_register_operand_serialize(const GRegisterOperand *, GAsmStorage *, packed_buffer *);
+
+
+
/* ---------------------------------------------------------------------------------- */
/* PUR REGISTRE DU MATERIEL */
/* ---------------------------------------------------------------------------------- */
@@ -301,9 +312,14 @@ static void g_register_operand_class_init(GRegisterOperandClass *klass)
object->dispose = (GObjectFinalizeFunc/* ! */)g_register_operand_dispose;
object->finalize = (GObjectFinalizeFunc)g_register_operand_finalize;
+ operand = G_ARCH_OPERAND_CLASS(klass);
+
operand->compare = (operand_compare_fc)g_register_operand_compare;
operand->print = (operand_print_fc)g_register_operand_print;
+ operand->unserialize = (unserialize_operand_fc)g_register_operand_unserialize;
+ operand->serialize = (serialize_operand_fc)g_register_operand_serialize;
+
}
@@ -495,3 +511,66 @@ bool g_register_operand_is_written(const GRegisterOperand *operand)
return operand->is_written;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* TRANSPOSITIONS VIA CACHE DES OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à constituer. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge un opérande depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_register_operand_unserialize(GRegisterOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchOperandClass *parent; /* Classe parente à consulter */
+
+ parent = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class);
+
+ result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde un opérande dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_register_operand_serialize(const GRegisterOperand *operand, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchOperandClass *parent; /* Classe parente à consulter */
+
+ parent = G_ARCH_OPERAND_CLASS(g_register_operand_parent_class);
+
+ result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf);
+
+ return result;
+
+}
diff --git a/src/arch/register.h b/src/arch/register.h
index f38698a..fb3741e 100644
--- a/src/arch/register.h
+++ b/src/arch/register.h
@@ -38,12 +38,12 @@
/* ---------------------------- PUR REGISTRE DU MATERIEL ---------------------------- */
-#define G_TYPE_ARCH_REGISTER g_arch_register_get_type()
-#define G_ARCH_REGISTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_register_get_type(), GArchRegister))
-#define G_IS_ARCH_REGISTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_register_get_type()))
-#define G_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_REGISTER, GArchRegisterClass))
-#define G_IS_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_REGISTER))
-#define G_ARCH_REGISTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_REGISTER, GArchRegisterClass))
+#define G_TYPE_ARCH_REGISTER g_arch_register_get_type()
+#define G_ARCH_REGISTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARCH_REGISTER, GArchRegister))
+#define G_IS_ARCH_REGISTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARCH_REGISTER))
+#define G_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARCH_REGISTER, GArchRegisterClass))
+#define G_IS_ARCH_REGISTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARCH_REGISTER))
+#define G_ARCH_REGISTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARCH_REGISTER, GArchRegisterClass))
/* Représentation d'un registre (instance) */
@@ -76,12 +76,12 @@ bool g_arch_register_is_stack_pointer(const GArchRegister *);
/* ------------------------- REGISTRE SOUS FORME D'OPERANDE ------------------------- */
-#define G_TYPE_REGISTER_OPERAND g_register_operand_get_type()
-#define G_REGISTER_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_register_operand_get_type(), GRegisterOperand))
-#define G_IS_REGISTER_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_register_operand_get_type()))
-#define G_REGISTER_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_REGISTER_OPERAND, GRegisterOperandClass))
-#define G_IS_REGISTER_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_REGISTER_OPERAND))
-#define G_REGISTER_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_REGISTER_OPERAND, GRegisterOperandClass))
+#define G_TYPE_REGISTER_OPERAND g_register_operand_get_type()
+#define G_REGISTER_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_REGISTER_OPERAND, GRegisterOperand))
+#define G_IS_REGISTER_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_REGISTER_OPERAND))
+#define G_REGISTER_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_REGISTER_OPERAND, GRegisterOperandClass))
+#define G_IS_REGISTER_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_REGISTER_OPERAND))
+#define G_REGISTER_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_REGISTER_OPERAND, GRegisterOperandClass))
/* Définition d'un opérande visant un registre (instance) */
diff --git a/src/arch/storage.c b/src/arch/storage.c
new file mode 100644
index 0000000..ac1c878
--- /dev/null
+++ b/src/arch/storage.c
@@ -0,0 +1,1593 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * storage.c - conservation hors mémoire vive des instructions désassemblées
+ *
+ * Copyright (C) 2018 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "storage.h"
+
+
+#include <assert.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#include "instruction.h"
+#include "target.h"
+#include "../common/compression.h"
+#include "../common/extstr.h"
+#include "../common/pathname.h"
+#include "../common/xdg.h"
+#include "../core/global.h"
+#include "../core/logs.h"
+#include "../core/queue.h"
+#include "../glibext/delayed-int.h"
+
+
+
+/* ----------------- CONSERVATION EXTERNE DES INSTRUCTIONS CHARGEES ----------------- */
+
+
+#define G_TYPE_INS_CACHING g_ins_caching_get_type()
+#define G_INS_CACHING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_INS_CACHING, GInsCaching))
+#define G_IS_INS_CACHING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_INS_CACHING))
+#define G_INS_CACHING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_INS_CACHING, GInsCachingClass))
+#define G_IS_INS_CACHING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_INS_CACHING))
+#define G_INS_CACHING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_INS_CACHING, GInsCachingClass))
+
+
+/* Ensembles binaires à désassembler (instance) */
+typedef struct _GInsCaching
+{
+ GDelayedWork parent; /* A laisser en premier */
+
+ GArchProcessor *proc; /* Ensemble à traiter */
+ GAsmStorage *storage; /* Cache de destinartion */
+
+ GBinFormat *format; /* Nature de l'opération */
+
+ bool status; /* Bilan de l'opération */
+
+} GInsCaching;
+
+/* Ensembles binaires à désassembler (classe) */
+typedef struct _GInsCachingClass
+{
+ GDelayedWorkClass parent; /* A laisser en premier */
+
+} GInsCachingClass;
+
+
+/* Indique le type défini pour les tâches d'enregistrement des instructions. */
+GType g_ins_caching_get_type(void);
+
+/* initialise la classe des tâches de cache d'instructions. */
+static void g_ins_caching_class_init(GInsCachingClass *);
+
+/* Initialise une tâche de cache d'instructions. */
+static void g_ins_caching_init(GInsCaching *);
+
+/* Supprime toutes les références externes. */
+static void g_ins_caching_dispose(GInsCaching *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_ins_caching_finalize(GInsCaching *);
+
+/* Crée une tâche de mise en cache de toutes les instructions. */
+static GInsCaching *g_ins_caching_new(GArchProcessor *, GAsmStorage *, GBinFormat *);
+
+/* Assure la conservation ou le chargement d'instructions. */
+static void g_ins_caching_process(GInsCaching *, GtkStatusStack *);
+
+/* Assure le chargement d'instructions en différé. */
+static void g_ins_caching_process_load(GInsCaching *, GtkStatusStack *);
+
+/* Assure la conservation d'instructions en différé. */
+static void g_ins_caching_process_store(GInsCaching *, GtkStatusStack *);
+
+/* Fournit le bilan des traitements d'instructions en différé. */
+static bool g_ins_caching_get_status(const GInsCaching *);
+
+
+
+/* ------------------- MECANISME DE SAUVEGARDE ET DE RESTAURATION ------------------- */
+
+
+/* Conservation d'une référence sur un type */
+typedef struct _gtype_ref_info_t
+{
+ GType gtype; /* Type pour la GLib */
+ gpointer gclass; /* Lien vers sa classe */
+
+} gtype_ref_info_t;
+
+/* Définition d'une conservation d'instructions d'assemblage (instance) */
+struct _GAsmStorage
+{
+ GObject parent; /* A laisser en premier */
+
+ char *id; /* Identifiant de contenu */
+
+ char *idx_filename; /* Fichier pour l'indexage */
+ char *ins_filename; /* Fichier pour instructions */
+ char *op_filename; /* Fichier pour les opérandes */
+ char *tp_filename; /* Fichier pour les types */
+
+ int idx_fd; /* Flux pour l'indexage */
+ int ins_fd; /* Flux pour les instructions */
+ int op_fd; /* Flux pour les opérandes */
+ int tp_fd; /* Flux pour les types */
+
+ /**
+ * La GLib n'est pas très claire sur la taille de GType :
+ *
+ * #if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus
+ * typedef gsize GType;
+ * #else // for historic reasons, C++ links against gulong GTypes
+ * typedef gulong GType;
+ * #endif
+ *
+ * Et :
+ *
+ * typedef unsigned $glib_size_type_define gsize;
+ *
+ * On prend le parti de réduire à 65536 types possibles dans l'enregistrement
+ * des objets instanciés, et on conserve ces types en tant qu'unsigned short.
+ */
+
+ gtype_ref_info_t *gtypes; /* Types des objets reconnus */
+ size_t gtp_count; /* Quantité de ces objets */
+ GMutex gtp_mutex; /* Contrôle d'accès à la liste */
+
+ GArchProcessor *proc; /* Ensemble à traiter */
+
+ GArchInstruction **collected; /* Liste d'instructions */
+ off64_t length; /* Taille de cette liste */
+ size_t count; /* Nombre de présences */
+
+};
+
+/* Définition d'une conservation d'instructions d'assemblage (classe) */
+struct _GAsmStorageClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ /* Signaux */
+
+ void (* saved) (GAsmStorage *);
+
+};
+
+
+/* Initialise la classe des conservations d'instructions. */
+static void g_asm_storage_class_init(GAsmStorageClass *);
+
+/* Initialise une instance de conservation d'instructions. */
+static void g_asm_storage_init(GAsmStorage *);
+
+/* Supprime toutes les références externes. */
+static void g_asm_storage_dispose(GAsmStorage *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_asm_storage_finalize(GAsmStorage *);
+
+/* Indique le chemin d'accès à l'archive finale. */
+static char *g_asm_storage_get_archive_filename(const GAsmStorage *);
+
+/* Décompresse les fichiers de cache d'instructions. */
+static bool g_asm_storage_decompress(const GAsmStorage *);
+
+/* Compresse les fichiers de cache d'instructions. */
+static bool g_asm_storage_compress(const GAsmStorage *);
+
+/* Apprend tous les types mémorisés dans un fichier. */
+static bool g_asm_storage_read_types(GAsmStorage *);
+
+/* Enregistre tous les types mémorisés dans un fichier. */
+static bool g_asm_storage_write_types(GAsmStorage *);
+
+/* Ouvre tous les fichiers nécessaires à une opération. */
+static bool g_asm_storage_open_files(GAsmStorage *, int );
+
+/* Acquitte la fin d'une tâche de sauvegarde complète. */
+static void on_cache_saving_completed(GInsCaching *, GAsmStorage *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION EXTERNE DES INSTRUCTIONS CHARGEES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour les tâches d'enregistrement des instructions. */
+G_DEFINE_TYPE(GInsCaching, g_ins_caching, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des tâches de cache d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_class_init(GInsCachingClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GDelayedWorkClass *work; /* Version en classe parente */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_ins_caching_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_ins_caching_finalize;
+
+ work = G_DELAYED_WORK_CLASS(klass);
+
+ work->run = (run_task_fc)g_ins_caching_process;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = instance à initialiser. *
+* *
+* Description : Initialise une tâche de cache d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_init(GInsCaching *caching)
+{
+ caching->status = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_dispose(GInsCaching *caching)
+{
+ g_object_unref(G_OBJECT(caching->proc));
+
+ g_object_unref(G_OBJECT(caching->storage));
+
+ if (caching->format != NULL)
+ g_object_unref(G_OBJECT(caching->format));
+
+ G_OBJECT_CLASS(g_ins_caching_parent_class)->dispose(G_OBJECT(caching));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_finalize(GInsCaching *caching)
+{
+ G_OBJECT_CLASS(g_ins_caching_parent_class)->finalize(G_OBJECT(caching));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : proc = gestionnaire de l'ensemble d'instructions visées. *
+* storage = gestionnaire de la conservation à venir. *
+* format = format binaire chargé associé à l'architecture. *
+* *
+* Description : Crée une tâche de mise en cache de toutes les instructions. *
+* *
+* Retour : Tâche créée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GInsCaching *g_ins_caching_new(GArchProcessor *proc, GAsmStorage *storage, GBinFormat *format)
+{
+ GInsCaching *result; /* Tâche à retourner */
+
+ result = g_object_new(G_TYPE_INS_CACHING, NULL);
+
+ result->proc = proc;
+ g_object_ref(G_OBJECT(result->proc));
+
+ result->storage = storage;
+ g_object_ref(G_OBJECT(result->storage));
+
+ result->format = format;
+
+ if (format != NULL)
+ g_object_ref(G_OBJECT(format));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = opération d'enregistrement à mener. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Assure la conservation ou le chargement d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_process(GInsCaching *caching, GtkStatusStack *status)
+{
+ if (caching->format != NULL)
+ g_ins_caching_process_load(caching, status);
+
+ else
+ g_ins_caching_process_store(caching, status);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = opération d'enregistrement à mener. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Assure le chargement d'instructions en différé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_process_load(GInsCaching *caching, GtkStatusStack *status)
+{
+ GAsmStorage *storage; /* Cache de destinartion */
+ packed_buffer pbuf; /* Tampon des données à écrire */
+ off64_t i; /* Boucle de parcours */
+ off64_t pos; /* Position courante */
+ GArchInstruction *instr; /* Instruction à traiter */
+ off64_t target; /* Position dans le flux */
+
+ storage = caching->storage;
+
+ init_packed_buffer(&pbuf);
+
+ for (i = 0; i < storage->length && caching->status; i++)
+ {
+ /* Des données sont-elles présentes à cette position ? */
+
+ pos = lseek64(storage->idx_fd, i * sizeof(off64_t), SEEK_SET);
+
+ if (pos != (i * sizeof(off64_t)))
+ {
+ perror("lseek64");
+ caching->status = false;
+ break;
+ }
+
+ caching->status = safe_read(storage->idx_fd, &target, sizeof(off64_t));
+
+ if (!caching->status)
+ break;
+
+ if (target == (off64_t)-1)
+ continue;
+
+ /* Chargement de l'instruction */
+
+ instr = g_asm_storage_get_instruction_at(storage, caching->format, i, &pbuf);
+
+ if (instr == NULL)
+ caching->status = false;
+
+ else
+ g_object_unref(G_OBJECT(instr));
+
+ }
+
+ exit_packed_buffer(&pbuf);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = opération d'enregistrement à mener. *
+* status = barre de statut à tenir informée. *
+* *
+* Description : Assure la conservation d'instructions en différé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_ins_caching_process_store(GInsCaching *caching, GtkStatusStack *status)
+{
+ GArchProcessor *proc; /* Ensemble à traiter */
+ GAsmStorage *storage; /* Cache de destinartion */
+ packed_buffer pbuf; /* Tampon des données à écrire */
+ size_t count; /* Quantité d'instructions */
+ phys_t last_phys; /* Dernière position physique */
+ size_t i; /* Boucle de parcours #1 */
+ GArchInstruction *instr; /* Instruction à traiter */
+ off64_t pos; /* Position dans le flux */
+ const mrange_t *irange; /* Emplacement de l'instruction*/
+ phys_t cur_phys; /* Position physique courante */
+ phys_t k; /* Boucle de parcours #2 */
+
+ proc = caching->proc;
+ storage = caching->storage;
+
+ init_packed_buffer(&pbuf);
+
+ g_arch_processor_lock(proc);
+
+ count = g_arch_processor_count_instructions(proc);
+
+ last_phys = VMPA_NO_PHYSICAL;
+
+ for (i = 0; i < count && caching->status; i++)
+ {
+ /* Enregistrement de l'instruction */
+
+ instr = g_arch_processor_get_instruction(proc, i);
+
+ caching->status = g_arch_instruction_store(instr, storage, &pbuf);
+
+ if (caching->status)
+ caching->status = g_asm_storage_store_instruction_data(storage, &pbuf, &pos);
+
+ /* Enregistrement de la position */
+
+ if (caching->status)
+ {
+ irange = g_arch_instruction_get_range(instr);
+
+ cur_phys = get_phy_addr(get_mrange_addr(irange));
+
+ assert((last_phys == VMPA_NO_PHYSICAL && cur_phys == 0) || (cur_phys > 0 && last_phys < cur_phys));
+
+ if (last_phys != VMPA_NO_PHYSICAL)
+ for (k = last_phys; k < (cur_phys - 1) && caching->status; k++)
+ caching->status = safe_write(storage->idx_fd, (off64_t []) { -1 }, sizeof(off64_t));
+
+ caching->status = safe_write(storage->idx_fd, &pos, sizeof(off64_t));
+
+ last_phys = cur_phys;
+
+ }
+
+ g_object_unref(G_OBJECT(instr));
+
+ }
+
+ g_arch_processor_unlock(proc);
+
+ exit_packed_buffer(&pbuf);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = opération d'enregistrement à mener. *
+* *
+* Description : Fournit le bilan des traitements d'instructions en différé. *
+* *
+* Retour : Bilan des opérations. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_ins_caching_get_status(const GInsCaching *caching)
+{
+ bool result; /* Bilan à retourner */
+
+ result = caching->status;
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MECANISME DE SAUVEGARDE ET DE RESTAURATION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conservation d'instructions d'assemblage. */
+G_DEFINE_TYPE(GAsmStorage, g_asm_storage, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des conservations d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_asm_storage_class_init(GAsmStorageClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_asm_storage_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_asm_storage_finalize;
+
+ g_signal_new("saved",
+ G_TYPE_ASM_STORAGE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GAsmStorageClass, saved),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = instance à initialiser. *
+* *
+* Description : Initialise une instance de conservation d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_asm_storage_init(GAsmStorage *storage)
+{
+ storage->idx_filename = NULL;
+ storage->ins_filename = NULL;
+ storage->op_filename = NULL;
+ storage->tp_filename = NULL;
+
+ storage->idx_fd = -1;
+ storage->ins_fd = -1;
+ storage->op_fd = -1;
+ storage->tp_fd = -1;
+
+ storage->gtypes = NULL;
+ storage->gtp_count = 0;
+ g_mutex_init(&storage->gtp_mutex);
+
+ storage->proc = NULL;
+
+ storage->collected = NULL;
+ storage->length = 0;
+ storage->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_asm_storage_dispose(GAsmStorage *storage)
+{
+ size_t i; /* Boucle de parcours */
+
+ g_mutex_lock(&storage->gtp_mutex);
+
+ for (i = 0; i < storage->gtp_count; i++)
+ if (storage->gtypes[i].gclass != NULL)
+ g_type_class_unref(storage->gtypes[i].gclass);
+
+ g_mutex_unlock(&storage->gtp_mutex);
+
+ g_mutex_clear(&storage->gtp_mutex);
+
+ if (storage->proc != NULL)
+ g_object_unref(G_OBJECT(storage->proc));
+
+ for (i = 0; i < storage->length; i++)
+ if (storage->collected[i] != NULL)
+ g_object_unref(G_OBJECT(storage->collected[i]));
+
+ G_OBJECT_CLASS(g_asm_storage_parent_class)->dispose(G_OBJECT(storage));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_asm_storage_finalize(GAsmStorage *storage)
+{
+ int ret; /* Bilan d'un appel */
+
+ free(storage->id);
+
+#define finalize_storage_file(f) \
+ if (f != NULL) \
+ { \
+ ret = access(f, W_OK); \
+ if (ret == 0) \
+ { \
+ ret = unlink(f); \
+ if (ret != 0) perror("unlink"); \
+ } \
+ free(f); \
+ }
+
+ finalize_storage_file(storage->idx_filename);
+ finalize_storage_file(storage->ins_filename);
+ finalize_storage_file(storage->op_filename);
+ finalize_storage_file(storage->tp_filename);
+
+ if (storage->idx_fd != -1)
+ close(storage->idx_fd);
+
+ if (storage->ins_fd != -1)
+ close(storage->ins_fd);
+
+ if (storage->op_fd != -1)
+ close(storage->op_fd);
+
+ if (storage->gtypes != NULL)
+ free(storage->gtypes);
+
+ if (storage->collected != NULL)
+ free(storage->collected);
+
+ G_OBJECT_CLASS(g_asm_storage_parent_class)->finalize(G_OBJECT(storage));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : proc = gestionnaire de l'ensemble d'instructions visées. *
+* id = identifiant pour la zone d'enregistrements. *
+* *
+* Description : Crée le support d'une conservation d'instructions. *
+* *
+* Retour : Mécanismes mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GAsmStorage *g_asm_storage_new_compressed(GArchProcessor *proc, const gchar *id)
+{
+ GAsmStorage *result; /* Structure à retourner */
+ char *suffix; /* Fin du nom de fichier */
+ char *basedir; /* Chemin d'accès */
+ bool status; /* Assurance de validité */
+
+ result = g_object_new(G_TYPE_ASM_STORAGE, NULL);
+
+ result->id = strdup(id);
+
+ result->proc = proc;
+ g_object_ref(G_OBJECT(proc));
+
+ suffix = strdup("chrysalide");
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ suffix = stradd(suffix, "cache");
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+
+ basedir = get_xdg_config_dir(suffix);
+
+ free(suffix);
+
+ status = mkpath(basedir);
+ if (!status) goto gasn_base_error;
+
+ asprintf(&result->idx_filename, "%s.%s-%s", basedir, id, "index.bin");
+ asprintf(&result->ins_filename, "%s.%s-%s", basedir, id, "instructions.bin");
+ asprintf(&result->op_filename, "%s.%s-%s", basedir, id, "operands.bin");
+ asprintf(&result->tp_filename, "%s.%s-%s", basedir, id, "types.bin");
+
+ free(basedir);
+
+ return result;
+
+ gasn_base_error:
+
+ g_object_unref(G_OBJECT(result));
+
+ free(basedir);
+
+ return NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à consulter. *
+* *
+* Description : Indique le chemin d'accès à l'archive finale. *
+* *
+* Retour : Nom de fichier à libérer, ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *g_asm_storage_get_archive_filename(const GAsmStorage *storage)
+{
+ char *result; /* Chemin d'accès à retourner */
+ char *suffix; /* Fin du nom de fichier */
+
+ suffix = strdup("chrysalide");
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ suffix = stradd(suffix, "cache");
+ suffix = stradd(suffix, G_DIR_SEPARATOR_S);
+ suffix = stradd(suffix, storage->id);
+ suffix = stradd(suffix, ".idb.tar.xz");
+
+ result = get_xdg_config_dir(suffix);
+
+ free(suffix);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à consulter. *
+* *
+* Description : Détermine si un cache d'instructions complet existe. *
+* *
+* Retour : Bilan de la détermination. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_asm_storage_has_cache(const GAsmStorage *storage)
+{
+ bool result; /* Bilan à faire remonter */
+ char *filename; /* Chemin d'accès à l'archive */
+ int ret; /* Résultat d'un test d'accès */
+
+ filename = g_asm_storage_get_archive_filename(storage);
+
+ ret = access(filename, R_OK);
+
+ result = (ret == 0);
+
+ free(filename);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* *
+* Description : Décompresse les fichiers de cache d'instructions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_asm_storage_decompress(const GAsmStorage *storage)
+{
+ bool result; /* Bilan à retourner */
+ char *filename; /* Chemin d'accès à l'archive */
+ struct archive *in; /* Archive à consulter */
+ int ret; /* Bilan d'un appel */
+ struct archive_entry *entry; /* Elément de l'archive */
+ const char *path; /* Désignation d'un fichier */
+
+ result = false;
+
+ filename = g_asm_storage_get_archive_filename(storage);
+
+ in = archive_read_new();
+ archive_read_support_filter_all(in);
+ archive_read_support_format_all(in);
+
+ ret = archive_read_open_filename(in, filename, 10240 /* ?! */);
+ if (ret != ARCHIVE_OK) goto gasd_bad_archive;
+
+ for (ret = archive_read_next_header(in, &entry);
+ ret == ARCHIVE_OK;
+ ret = archive_read_next_header(in, &entry))
+ {
+ path = archive_entry_pathname(entry);
+
+ if (strcmp(path, "index.bin") == 0)
+ {
+ if (!dump_archive_entry_into_file(in, entry, storage->idx_filename))
+ goto gasd_exit;
+ }
+ else if (strcmp(path, "instructions.bin") == 0)
+ {
+ if (!dump_archive_entry_into_file(in, entry, storage->ins_filename))
+ goto gasd_exit;
+ }
+ else if (strcmp(path, "operands.bin") == 0)
+ {
+ if (!dump_archive_entry_into_file(in, entry, storage->op_filename))
+ goto gasd_exit;
+ }
+ else if (strcmp(path, "types.bin") == 0)
+ {
+ if (!dump_archive_entry_into_file(in, entry, storage->tp_filename))
+ goto gasd_exit;
+ }
+
+ }
+
+ if (ret != ARCHIVE_EOF)
+ goto gasd_exit;
+
+ result = true;
+
+ gasd_exit:
+
+ gasd_bad_archive:
+
+ archive_read_close(in);
+ archive_read_free(in);
+
+ free(filename);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* *
+* Description : Compresse les fichiers de cache d'instructions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_asm_storage_compress(const GAsmStorage *storage)
+{
+ bool result; /* Bilan à retourner */
+ char *filename; /* Chemin d'accès à l'archive */
+ struct archive *out; /* Archive à constituer */
+ int ret; /* Bilan d'une création */
+ CPError status; /* Bilan d'une compression */
+
+ result = false;
+
+ filename = g_asm_storage_get_archive_filename(storage);
+
+ out = archive_write_new();
+ archive_write_add_filter_xz(out);
+ archive_write_set_format_gnutar(out);
+
+ ret = archive_write_open_filename(out, filename);
+ if (ret != ARCHIVE_OK) goto gasc_exit;
+
+ status = add_file_into_archive(out, storage->idx_filename, "index.bin");
+ if (status != CPE_NO_ERROR) goto gasc_exit;
+
+ status = add_file_into_archive(out, storage->ins_filename, "instructions.bin");
+ if (status != CPE_NO_ERROR) goto gasc_exit;
+
+ status = add_file_into_archive(out, storage->op_filename, "operands.bin");
+ if (status != CPE_NO_ERROR) goto gasc_exit;
+
+ status = add_file_into_archive(out, storage->tp_filename, "types.bin");
+ if (status != CPE_NO_ERROR) goto gasc_exit;
+
+ result = true;
+
+ gasc_exit:
+
+ archive_write_close(out);
+ archive_write_free(out);
+
+ free(filename);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à compléter. *
+* *
+* Description : Apprend tous les types mémorisés dans un fichier. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_asm_storage_read_types(GAsmStorage *storage)
+{
+ bool result; /* Bilan à enregistrer */
+ packed_buffer pbuf; /* Tampon des données à écrire */
+ size_t i; /* Boucle de parcours */
+ unsigned char len; /* Taille d'un nom de type */
+ char *name; /* Désignation d'un type */
+
+ init_packed_buffer(&pbuf);
+
+ result = read_packed_buffer(&pbuf, storage->tp_fd);
+
+ if (result)
+ {
+ g_mutex_lock(&storage->gtp_mutex);
+
+ result = extract_packed_buffer(&pbuf, &storage->gtp_count, sizeof(size_t), true);
+
+ if (result)
+ storage->gtypes = (gtype_ref_info_t *)calloc(storage->gtp_count, sizeof(gtype_ref_info_t));
+
+ for (i = 0; i < storage->gtp_count && result; i++)
+ {
+ result = extract_packed_buffer(&pbuf, &len, sizeof(unsigned char), false);
+
+ if (result)
+ {
+ name = (char *)malloc(len);
+
+ result = extract_packed_buffer(&pbuf, name, len, false);
+
+ if (result)
+ {
+ storage->gtypes[i].gtype = g_type_from_name(name);
+ result = (storage->gtypes[i].gtype != 0);
+
+ if (!result)
+ log_variadic_message(LMT_ERROR, "Unknown type: '%s'", name);
+
+ }
+
+ if (result)
+ storage->gtypes[i].gclass = g_type_class_ref(storage->gtypes[i].gtype);
+
+ free(name);
+
+ }
+
+ }
+
+ g_mutex_unlock(&storage->gtp_mutex);
+
+ }
+
+ exit_packed_buffer(&pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* pbuf = zone tampon à venir lire. *
+* *
+* Description : Crée une nouvelle instance d'objet à partir de son type. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GObject *g_asm_storage_create_object(GAsmStorage *storage, packed_buffer *pbuf)
+{
+ GObject *result; /* Nouvelle instance à renvoyer*/
+ size_t index; /* Indice du point d'insertion */
+ bool status; /* Bilan d'une récupération */
+
+ result = NULL;
+
+ status = extract_packed_buffer(pbuf, &index, sizeof(size_t), true);
+
+ if (status)
+ {
+ g_mutex_lock(&storage->gtp_mutex);
+
+ if (index < storage->gtp_count)
+ result = g_object_new(storage->gtypes[index].gtype, NULL);
+
+ g_mutex_unlock(&storage->gtp_mutex);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* obj = instance dont le type est à mémoriser. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde le type d'un objet instancié. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_asm_storage_store_object_gtype(GAsmStorage *storage, GObject *obj, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GType gtype; /* Type à enregistrer */
+ size_t index; /* Indice du point d'insertion */
+
+ gtype = G_TYPE_FROM_INSTANCE(obj);
+
+ /**
+ * Pour quelques explications sur l'esquive suivante, se rapporter aux
+ * commentaires de g_target_operand_unserialize().
+ *
+ * Dans la situation présente, on ne doit pas enregistrer le type dans le tampon,
+ * car l'opérande va relancer l'opération entière (avec un opérande temporaire),
+ * ce qui conduirait à l'enregistrement de deux types successifs dans les données.
+ */
+
+ if (gtype == G_TYPE_TARGET_OPERAND)
+ result = true;
+
+ else
+ {
+ g_mutex_lock(&storage->gtp_mutex);
+
+ for (index = 0; index < storage->gtp_count; index++)
+ if (storage->gtypes[index].gtype == gtype)
+ break;
+
+ if (index == storage->gtp_count)
+ {
+ storage->gtypes = (gtype_ref_info_t *)realloc(storage->gtypes,
+ ++storage->gtp_count * sizeof(gtype_ref_info_t));
+
+ assert(storage->gtp_count > 0);
+
+ storage->gtypes[index].gtype = gtype;
+ storage->gtypes[index].gclass = g_type_class_ref(gtype);
+
+ }
+
+ g_mutex_unlock(&storage->gtp_mutex);
+
+ result = extend_packed_buffer(pbuf, &index, sizeof(size_t), true);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à consulter. *
+* *
+* Description : Enregistre tous les types mémorisés dans un fichier. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_asm_storage_write_types(GAsmStorage *storage)
+{
+ bool result; /* Bilan à enregistrer */
+ packed_buffer pbuf; /* Tampon des données à écrire */
+ size_t i; /* Boucle de parcours */
+ const gchar *name; /* Désignation d'un type */
+ size_t len; /* Taille de ce nom */
+
+ init_packed_buffer(&pbuf);
+
+ g_mutex_lock(&storage->gtp_mutex);
+
+ result = extend_packed_buffer(&pbuf, &storage->gtp_count, sizeof(size_t), true);
+
+ for (i = 0; i < storage->gtp_count && result; i++)
+ {
+ name = g_type_name(storage->gtypes[i].gtype);
+ len = strlen(name) + 1;
+
+ if (len > (2 << (sizeof(unsigned char) * 8 - 1)))
+ {
+ log_variadic_message(LMT_ERROR, "Type name too long: '%s' (%zu bytes)", name, len);
+ result = false;
+ break;
+ }
+
+ result = extend_packed_buffer(&pbuf, (unsigned char []) { len }, sizeof(unsigned char), false);
+
+ if (result)
+ result = extend_packed_buffer(&pbuf, name, len, false);
+
+ }
+
+ if (result)
+ result = write_packed_buffer(&pbuf, storage->tp_fd);
+
+ g_mutex_unlock(&storage->gtp_mutex);
+
+ exit_packed_buffer(&pbuf);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* ins = true si les données viennent d'une instruction. *
+* pbuf = zone tampon à remplir. *
+* pos = tête de lecture avant écriture. *
+* *
+* Description : Charge des données rassemblées. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool _g_asm_storage_load_data(const GAsmStorage *storage, bool ins, packed_buffer *pbuf, off64_t pos)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ciblé */
+ off64_t new; /* Nouvelle position de lecture*/
+
+ fd = ins ? storage->ins_fd : storage->op_fd;
+
+ new = lseek64(fd, pos, SEEK_SET);
+
+ if (new != pos)
+ result = false;
+
+ else
+ {
+ reset_packed_buffer(pbuf);
+ result = read_packed_buffer(pbuf, fd);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* ins = true si les données viennent d'une instruction. *
+* pbuf = zone tampon à lire. *
+* pos = tête de lecture avant écriture. [OUT] *
+* *
+* Description : Sauvegarde des données rassemblées. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool _g_asm_storage_store_data(const GAsmStorage *storage, bool ins, packed_buffer *pbuf, off64_t *pos)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ciblé */
+
+ fd = ins ? storage->ins_fd : storage->op_fd;
+
+ *pos = lseek64(fd, 0, SEEK_CUR);
+
+ if (*pos == (off64_t)-1)
+ result = false;
+
+ else
+ {
+ result = write_packed_buffer(pbuf, fd);
+ reset_packed_buffer(pbuf);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* flags = options d'ouverture supplémentaires. *
+* *
+* Description : Ouvre tous les fichiers nécessaires à une opération. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_asm_storage_open_files(GAsmStorage *storage, int flags)
+{
+ bool result; /* Bilan à retourner */
+
+#define open_file(filename, fd) \
+ ({ \
+ bool __status; \
+ fd = open(filename, flags | O_LARGEFILE, 0600); \
+ if (fd == -1) \
+ { \
+ perror("open"); \
+ __status = false; \
+ } \
+ else \
+ __status = true; \
+ __status; \
+ })
+
+ result = open_file(storage->idx_filename, storage->idx_fd);
+
+ if (result)
+ result = open_file(storage->ins_filename, storage->ins_fd);
+
+ if (result)
+ result = open_file(storage->op_filename, storage->op_fd);
+
+ if (result)
+ result = open_file(storage->tp_filename, storage->tp_fd);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* gid = groupe de travail dédié. *
+* *
+* Description : Lance une restauration complète d'unsauvegarde compressée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_asm_storage_open(GAsmStorage *storage, GBinFormat *format, wgroup_id_t gid)
+{
+ bool result; /* Bilan à retourner */
+ GInsCaching *caching; /* Tâche à faire exécuter */
+ GWorkQueue *queue; /* Gestionnaire des tâches */
+ GArchInstruction **list; /* Instructions rechargées */
+ size_t i; /* Boucle de parcours #1 */
+ size_t k; /* Boucle de parcours #2 */
+
+ result = g_asm_storage_decompress(storage);
+
+ if (result)
+ result = g_asm_storage_open_files(storage, O_RDONLY);
+
+ if (result)
+ result = g_asm_storage_read_types(storage);
+
+ if (result)
+ {
+ storage->length = lseek64(storage->idx_fd, 0, SEEK_END);
+
+ if (storage->length == (off64_t)-1)
+ {
+ perror("lseek64");
+ result = false;
+ goto gaso_exit;
+ }
+
+ result = (storage->length % sizeof(off64_t) == 0);
+
+ storage->length /= sizeof(off64_t);
+
+ }
+
+ if (!result)
+ {
+ log_simple_message(LMT_ERROR, "Instruction cache seems corrupted...");
+ goto gaso_exit;
+ }
+
+ storage->collected = (GArchInstruction **)calloc(storage->length, sizeof(GArchInstruction *));
+
+ /**
+ * Cette méthode ne peut être appelée que pour un objet construit
+ * à partir du constructeur g_asm_storage_new_compressed().
+ */
+ assert(storage->proc != NULL);
+
+ caching = g_ins_caching_new(storage->proc, storage, format);
+ g_object_ref(G_OBJECT(caching));
+
+ queue = get_work_queue();
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(caching), gid);
+
+ g_work_queue_wait_for_completion(queue, gid);
+
+ result = g_ins_caching_get_status(caching);
+
+ g_object_unref(G_OBJECT(caching));
+
+
+ if (result)
+ {
+ log_simple_message(LMT_INFO, "Successfully restored all instructions from cache!");
+
+ list = (GArchInstruction **)malloc(storage->count * sizeof(GArchInstruction *));
+
+ for (i = 0, k = 0; i < storage->length; i++)
+ if (storage->collected[i] != NULL)
+ {
+ list[k] = storage->collected[i];
+ g_object_ref(G_OBJECT(list[k++]));
+ }
+
+ assert(k == storage->count);
+
+ g_arch_processor_set_instructions(storage->proc, list, storage->count);
+
+ }
+
+ else
+ log_simple_message(LMT_ERROR, "Failed to restore all instructions from cache!");
+
+ gaso_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* index = position physique de l'instruction recherchée. *
+* pbuf = tampon de lecture à disposition pour l'opération. *
+* *
+* Description : Fournit l'instruction correspondant à une position indicée. *
+* *
+* Retour : Instruction rechargée ou NULL en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GArchInstruction *g_asm_storage_get_instruction_at(GAsmStorage *storage, GBinFormat *format, off64_t index, packed_buffer *pbuf)
+{
+ GArchInstruction *result; /* Instruction à renvoyer */
+ off64_t pos; /* Position dans le cache */
+ off64_t new; /* Nouvelle position de lecture*/
+ off64_t target; /* Emplacement du cache ciblé */
+ bool status; /* Bilan d'une lecture */
+#ifndef NDEBUG
+ const mrange_t *irange; /* Emplacement de l'instruction*/
+#endif
+
+ assert(index < storage->length);
+
+ pos = index * sizeof(off64_t);
+
+ if (storage->collected[index] == NULL)
+ {
+ new = lseek64(storage->idx_fd, pos, SEEK_SET);
+
+ if (new == pos)
+ {
+ status = safe_read(storage->idx_fd, &target, sizeof(off64_t));
+
+ if (status)
+ status = g_asm_storage_load_instruction_data(storage, pbuf, target);
+
+ if (status)
+ storage->collected[index] = g_arch_instruction_load(storage, format, pbuf);
+
+ if (storage->collected[index] != NULL)
+ {
+ storage->count++;
+
+#ifndef NDEBUG
+ irange = g_arch_instruction_get_range(storage->collected[index]);
+
+ assert(index == get_phy_addr(get_mrange_addr(irange)));
+#endif
+
+ }
+
+ }
+
+ }
+
+ result = storage->collected[index];
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gestionnaire à manipuler. *
+* *
+* Description : Programme une sauvegarde complète et compressée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_asm_storage_save(GAsmStorage *storage)
+{
+ bool status; /* Statut des préparatifs */
+ GInsCaching *caching; /* Tâche à faire exécuter */
+ GWorkQueue *queue; /* Gestionnaire des tâches */
+
+ status = g_asm_storage_open_files(storage, O_WRONLY | O_CREAT | O_TRUNC);
+
+ if (!status)
+ log_simple_message(LMT_ERROR, "Unable to setup files for instructions caching!");
+
+ else
+ {
+ /**
+ * Cette méthode ne peut être appelée que pour un objet construit
+ * à partir du constructeur g_asm_storage_new_compressed().
+ */
+ assert(storage->proc != NULL);
+
+ caching = g_ins_caching_new(storage->proc, storage, NULL);
+
+ g_signal_connect(caching, "work-completed", G_CALLBACK(on_cache_saving_completed), storage);
+
+ queue = get_work_queue();
+
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(caching), STORAGE_WORK_GROUP);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : caching = tâche de sauvegarde menée à son terme. *
+* storage = gestionnaire de conservation à la réception. *
+* *
+* Description : Acquitte la fin d'une tâche de sauvegarde complète. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_cache_saving_completed(GInsCaching *caching, GAsmStorage *storage)
+{
+ bool status; /* Bilan des enregistrements */
+
+ status = g_ins_caching_get_status(caching);
+
+ if (status)
+ log_simple_message(LMT_INFO, "Successfully cached all instructions!");
+ else
+ log_simple_message(LMT_ERROR, "Failed to cache all instructions!");
+
+ if (status)
+ status = g_asm_storage_write_types(storage);
+
+ if (status)
+ {
+ status = g_asm_storage_compress(storage);
+
+ if (!status)
+ log_simple_message(LMT_ERROR, "Failed to compress instruction cache!");
+
+ }
+
+ g_signal_emit_by_name(storage, "saved");
+
+}
diff --git a/src/arch/storage.h b/src/arch/storage.h
new file mode 100644
index 0000000..002897a
--- /dev/null
+++ b/src/arch/storage.h
@@ -0,0 +1,104 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * storage.h - prototypes pour la conservation hors mémoire vive des instructions désassemblées
+ *
+ * Copyright (C) 2018 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ARCH_STORAGE_H
+#define _ARCH_STORAGE_H
+
+
+#include <glib-object.h>
+
+
+#include <stdbool.h>
+
+
+#include "processor.h"
+
+
+
+/* ------------------- MECANISME DE SAUVEGARDE ET DE RESTAURATION ------------------- */
+
+
+/* Définition générique d'une instruction d'architecture (instance) */
+typedef struct _GArchInstruction GArchInstruction;
+
+
+#define G_TYPE_ASM_STORAGE g_asm_storage_get_type()
+#define G_ASM_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ASM_STORAGE, GAsmStorage))
+#define G_IS_ASM_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ASM_STORAGE))
+#define G_ASM_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ASM_STORAGE, GAsmStorageClass))
+#define G_IS_ASM_STORAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ASM_STORAGE))
+#define G_ASM_STORAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ASM_STORAGE, GAsmStorageClass))
+
+
+/* Définition d'une conservation d'instructions d'assemblage (instance) */
+typedef struct _GAsmStorage GAsmStorage;
+
+/* Définition d'une conservation d'instructions d'assemblage (classe) */
+typedef struct _GAsmStorageClass GAsmStorageClass;
+
+
+/* Indique le type défini pour une conservation d'instructions d'assemblage. */
+GType g_asm_storage_get_type(void);
+
+/* Crée le support d'une conservation d'instructions. */
+GAsmStorage *g_asm_storage_new_compressed(GArchProcessor *, const gchar *);
+
+/* Détermine si un cache d'instructions complet existe. */
+bool g_asm_storage_has_cache(const GAsmStorage *);
+
+/* Crée une nouvelle instance d'objet à partir de son type. */
+GObject *g_asm_storage_create_object(GAsmStorage *, packed_buffer *);
+
+/* Sauvegarde le type d'un objet instancié. */
+bool g_asm_storage_store_object_gtype(GAsmStorage *, GObject *, packed_buffer *);
+
+/* Charge des données rassemblées. */
+bool _g_asm_storage_load_data(const GAsmStorage *, bool, packed_buffer *, off64_t);
+
+#define g_asm_storage_load_instruction_data(s, b, p) \
+ _g_asm_storage_load_data(s, true, b, p)
+
+#define g_asm_storage_load_operand_data(s, b, p) \
+ _g_asm_storage_load_data(s, false, b, p)
+
+/* Sauvegarde des données rassemblées. */
+bool _g_asm_storage_store_data(const GAsmStorage *, bool, packed_buffer *, off64_t *);
+
+#define g_asm_storage_store_instruction_data(s, b, p) \
+ _g_asm_storage_store_data(s, true, b, p)
+
+#define g_asm_storage_store_operand_data(s, b, p) \
+ _g_asm_storage_store_data(s, false, b, p)
+
+/* Lance une restauration complète d'unsauvegarde compressée. */
+bool g_asm_storage_open(GAsmStorage *, GBinFormat *, wgroup_id_t);
+
+/* Fournit l'instruction correspondant à une position indicée. */
+GArchInstruction *g_asm_storage_get_instruction_at(GAsmStorage *, GBinFormat *, off64_t, packed_buffer *);
+
+/* Programme une sauvegarde complète et compressée. */
+void g_asm_storage_save(GAsmStorage *);
+
+
+
+#endif /* _ARCH_STORAGE_H */
diff --git a/src/arch/target.c b/src/arch/target.c
index 3b5655e..a297a3c 100644
--- a/src/arch/target.c
+++ b/src/arch/target.c
@@ -47,6 +47,7 @@ struct _GTargetOperand
MemoryDataSize size; /* Taille de l'opérande */
vmpa2t addr; /* Adresse de l'élément visé */
+ bool strict; /* Résolution stricte */
GBinSymbol *symbol; /* Eventuel symbole associé */
phys_t diff; /* Position dans le symbole */
@@ -84,6 +85,17 @@ static char *g_target_operand_build_tooltip(const GTargetOperand *, const GLoade
+/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */
+
+
+/* Charge un opérande depuis une mémoire tampon. */
+static bool g_target_operand_unserialize(GTargetOperand *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde un opérande dans une mémoire tampon. */
+static bool g_target_operand_serialize(const GTargetOperand *, GAsmStorage *, packed_buffer *);
+
+
+
/* Indique le type défini pour un opérande de valeur numérique. */
G_DEFINE_TYPE(GTargetOperand, g_target_operand, G_TYPE_ARCH_OPERAND);
@@ -116,6 +128,9 @@ static void g_target_operand_class_init(GTargetOperandClass *klass)
operand->print = (operand_print_fc)g_target_operand_print;
operand->build_tooltip = (operand_build_tooltip_fc)g_target_operand_build_tooltip;
+ operand->unserialize = (unserialize_operand_fc)g_target_operand_unserialize;
+ operand->serialize = (serialize_operand_fc)g_target_operand_serialize;
+
}
@@ -136,6 +151,7 @@ static void g_target_operand_init(GTargetOperand *operand)
operand->size = MDS_UNDEFINED;
init_vmpa(&operand->addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL);
+ operand->strict = true;
operand->symbol = NULL;
operand->diff = 0;
@@ -324,6 +340,8 @@ GArchOperand *g_target_operand_new(MemoryDataSize size, const vmpa2t *addr)
result = g_object_new(G_TYPE_TARGET_OPERAND, NULL);
+ assert(size != MDS_UNDEFINED);
+
result->size = size;
copy_vmpa(&result->addr, addr);
@@ -466,8 +484,12 @@ bool g_target_operand_resolve(GTargetOperand *operand, GBinFormat *format, bool
if (operand->symbol != NULL)
g_object_unref(G_OBJECT(operand->symbol));
+ operand->strict = strict;
+
result = g_binary_format_resolve_symbol(format, &operand->addr, strict, &operand->symbol, &operand->diff);
+ assert(!result || !strict || (strict && operand->diff == 0));
+
/**
* Si plusieurs chaînes se suivent, la seconde et les suivantes bénéficient
* d'une étiquette si et seulement si elles sont détachées des précédentes
@@ -539,3 +561,85 @@ GBinSymbol *g_target_operand_get_symbol(const GTargetOperand *operand, phys_t *d
return result;
}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* TRANSPOSITIONS VIA CACHE DES OPERANDES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à constituer. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge un opérande depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_target_operand_unserialize(GTargetOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+
+ assert(false);
+
+ /**
+ * Comme ce type d'opérande peut générer de nouveaux symboles lorsque
+ * sa résolution échoue, il faut appeler ces résolutions dans les contextes
+ * d'origine.
+ *
+ * Ces contextes sont généralement le lieu de conversions de valeurs immédiates
+ * en valeurs de cibles, donc la sérialisation de l'opérande conduit à
+ * la sauvegarde d'un opérande de valeur immédiate de subsitution.
+ *
+ * La désérialisation est donc prise en compte par ce dernier type d'opérande.
+ */
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : operand = opérande d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde un opérande dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_target_operand_serialize(const GTargetOperand *operand, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchOperand *original; /* Opérande d'origine */
+
+ /**
+ * Pour les architectures sans mémoire virtuelle, la valeur est portée
+ * par la position physique.
+ */
+
+ if (has_virt_addr(&operand->addr))
+ original = g_imm_operand_new_from_value(operand->size, get_virt_addr(&operand->addr));
+ else
+ original = g_imm_operand_new_from_value(operand->size, get_phy_addr(&operand->addr));
+
+ result = g_arch_operand_store(original, storage, pbuf);
+
+ g_object_unref(G_OBJECT(original));
+
+ return result;
+
+}
diff --git a/src/arch/target.h b/src/arch/target.h
index 45c1cb0..3c68fda 100644
--- a/src/arch/target.h
+++ b/src/arch/target.h
@@ -32,16 +32,15 @@
#include "archbase.h"
#include "operand.h"
#include "vmpa.h"
-#include "../format/format.h"
-#define G_TYPE_TARGET_OPERAND g_target_operand_get_type()
-#define G_TARGET_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_target_operand_get_type(), GTargetOperand))
-#define G_IS_TARGET_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_target_operand_get_type()))
-#define G_TARGET_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TARGET_OPERAND, GTargetOperandClass))
-#define G_IS_TARGET_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TARGET_OPERAND))
-#define G_TARGET_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TARGET_OPERAND, GTargetOperandClass))
+#define G_TYPE_TARGET_OPERAND g_target_operand_get_type()
+#define G_TARGET_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_TARGET_OPERAND, GTargetOperand))
+#define G_IS_TARGET_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_TARGET_OPERAND))
+#define G_TARGET_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TARGET_OPERAND, GTargetOperandClass))
+#define G_IS_TARGET_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TARGET_OPERAND))
+#define G_TARGET_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TARGET_OPERAND, GTargetOperandClass))
/* Définition d'un opérande ciblant idéalement un symbole connu (instance) */
diff --git a/src/arch/undefined.c b/src/arch/undefined.c
index 656e3f5..5542ac2 100644
--- a/src/arch/undefined.c
+++ b/src/arch/undefined.c
@@ -69,6 +69,22 @@ static const char *g_undef_instruction_get_encoding(const GUndefInstruction *);
/* Fournit le nom humain de l'instruction manipulée. */
static const char *g_undef_instruction_get_keyword(const GUndefInstruction *, AsmSyntax);
+
+
+/* -------------------- CONSERVATION SUR DISQUE DES INSTRUCTIONS -------------------- */
+
+
+/* Charge une instruction depuis une mémoire tampon. */
+static bool g_undef_instruction_unserialize(GUndefInstruction *, GAsmStorage *, GBinFormat *, packed_buffer *);
+
+/* Sauvegarde une instruction dans une mémoire tampon. */
+static bool g_undef_instruction_serialize(GUndefInstruction *, GAsmStorage *, packed_buffer *);
+
+
+
+/* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */
+
+
/* Ajoute à un tampon GLib le contenu de l'instance spécifiée. */
static void g_undef_instruction_print(GUndefInstruction *, GBufferLine *, size_t, size_t, const GBinContent *);
@@ -109,6 +125,10 @@ static void g_undef_instruction_class_init(GUndefInstructionClass *klass)
instr->get_encoding = (get_instruction_encoding_fc)g_undef_instruction_get_encoding;
instr->get_keyword = (get_instruction_keyword_fc)g_undef_instruction_get_keyword;
+
+ instr->unserialize = (unserialize_instruction_fc)g_undef_instruction_unserialize;
+ instr->serialize = (serialize_instruction_fc)g_undef_instruction_serialize;
+
instr->print = (print_instruction_fc)g_undef_instruction_print;
}
@@ -261,6 +281,81 @@ const char *g_undef_instruction_get_keyword(const GUndefInstruction *instr, AsmS
}
+
+/* ---------------------------------------------------------------------------------- */
+/* CONSERVATION SUR DISQUE DES INSTRUCTIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* format = format binaire chargé associé à l'architecture. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Charge une instruction depuis une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_undef_instruction_unserialize(GUndefInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchInstructionClass *parent; /* Classe parente à consulter */
+
+ parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class);
+
+ result = parent->unserialize(G_ARCH_INSTRUCTION(instr), storage, format, pbuf);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, &instr->status, sizeof(InstrBehaviorStatus), true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instr = instruction d'assemblage à consulter. *
+* storage = mécanisme de sauvegarde à manipuler. *
+* pbuf = zone tampon à remplir. *
+* *
+* Description : Sauvegarde une instruction dans une mémoire tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_undef_instruction_serialize(GUndefInstruction *instr, GAsmStorage *storage, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ GArchInstructionClass *parent; /* Classe parente à consulter */
+
+ parent = G_ARCH_INSTRUCTION_CLASS(g_undef_instruction_parent_class);
+
+ result = parent->serialize(G_ARCH_INSTRUCTION(instr), storage, pbuf);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, &instr->status, sizeof(InstrBehaviorStatus), true);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* OFFRE DE CAPACITES DE GENERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
/******************************************************************************
* *
* Paramètres : instr = instruction d'assemblage à représenter. *
diff --git a/src/arch/undefined.h b/src/arch/undefined.h
index 9992ce7..74db9fa 100644
--- a/src/arch/undefined.h
+++ b/src/arch/undefined.h
@@ -33,12 +33,12 @@
-#define G_TYPE_UNDEF_INSTRUCTION g_undef_instruction_get_type()
-#define G_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_undef_instruction_get_type(), GUndefInstruction))
-#define G_IS_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_undef_instruction_get_type()))
-#define G_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass))
-#define G_IS_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNDEF_INSTRUCTION))
-#define G_UNDEF_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass))
+#define G_TYPE_UNDEF_INSTRUCTION g_undef_instruction_get_type()
+#define G_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstruction))
+#define G_IS_UNDEF_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UNDEF_INSTRUCTION))
+#define G_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass))
+#define G_IS_UNDEF_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNDEF_INSTRUCTION))
+#define G_UNDEF_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNDEF_INSTRUCTION, GUndefInstructionClass))
/* Définition générique d'une instruction au comportement non défini (instance) */
diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c
index b29bb72..7abb5de 100644
--- a/src/arch/vmpa.c
+++ b/src/arch/vmpa.c
@@ -415,7 +415,7 @@ phys_t compute_vmpa_diff(const vmpa2t *a, const vmpa2t *b)
* Paramètres : addr = élément à venir lire. [OUT] *
* pbuf = paquet de données où venir puiser les infos. *
* *
-* Description : Lit la définition d'une adresse depuis un flux réseau. *
+* Description : Lit la définition d'une adresse depuis un tampon. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -442,7 +442,7 @@ bool unpack_vmpa(vmpa2t *addr, packed_buffer *pbuf)
* Paramètres : addr = élément à venir écrire. *
* pbuf = paquet de données où venir inscrire les infos. *
* *
-* Description : Ecrit la définition d'une adresse dans un flux réseau. *
+* Description : Ecrit la définition d'une adresse dans un tampon. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -1283,6 +1283,60 @@ void compute_mrange_end_addr(const mrange_t *range, vmpa2t *addr)
/******************************************************************************
* *
+* Paramètres : range = élément à venir lire. [OUT] *
+* pbuf = paquet de données où venir puiser les infos. *
+* *
+* Description : Lit la définition d'une couverture depuis un tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool unpack_mrange(mrange_t *range, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+
+ result = unpack_vmpa(&range->addr, pbuf);
+
+ if (result)
+ result = extract_packed_buffer(pbuf, (uint64_t *)&range->length, sizeof(uint64_t), true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : range = élément à venir écrire. *
+* pbuf = paquet de données où venir inscrire les infos. *
+* *
+* Description : Ecrit la définition d'une couverture dans un tampon. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool pack_mrange(const mrange_t *range, packed_buffer *pbuf)
+{
+ bool result; /* Bilan à retourner */
+
+ result = pack_vmpa(&range->addr, pbuf);
+
+ if (result)
+ result = extend_packed_buffer(pbuf, (uint64_t *)&range->length, sizeof(uint64_t), true);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : rane = emplacement virtuel ou physique à traiter. *
* msize = taille de cette adresse, réelle ou désirée. *
* start = indique si le début ou la fin est à imprimer. *
diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h
index 96fb52b..a1c60dd 100644
--- a/src/arch/vmpa.h
+++ b/src/arch/vmpa.h
@@ -121,10 +121,10 @@ void align_vmpa(vmpa2t *, phys_t);
/* Calcule au mieux la distance entre deux coordonnées. */
phys_t compute_vmpa_diff(const vmpa2t *, const vmpa2t *);
-/* Lit la définition d'une adresse depuis un flux réseau. */
+/* Lit la définition d'une adresse depuis un tampon. */
bool unpack_vmpa(vmpa2t *, packed_buffer *);
-/* Ecrit la définition d'une adresse dans un flux réseau. */
+/* Ecrit la définition d'une adresse dans un tampon. */
bool pack_vmpa(const vmpa2t *, packed_buffer *);
/* Transforme une adresse physique en chaîne de caractères. */
@@ -227,6 +227,12 @@ bool mrange_intersects_mrange(const mrange_t *, const mrange_t *);
/* Calcule la position extérieure finale d'une couverture. */
void compute_mrange_end_addr(const mrange_t *, vmpa2t *);
+/* Lit la définition d'une couverture depuis un tampon. */
+bool unpack_mrange(mrange_t *, packed_buffer *);
+
+/* Ecrit la définition d'une couverture dans un tampon. */
+bool pack_mrange(const mrange_t *, packed_buffer *);
+
/* Transforme un emplacement physique en chaîne de caractères. */
char *mrange_phys_to_string(const mrange_t *, MemoryDataSize, bool, char [VMPA_MAX_LEN], size_t *);