From 62f178cc3dcc889d56ba6d94f6fc8bba7b503c1a Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 31 Jan 2020 00:23:16 +0100
Subject: Compressed some architecture instruction properties.

---
 plugins/arm/v7/instruction.c            |   2 +-
 plugins/dalvik/pseudo/fill.c            |   2 +-
 plugins/dalvik/pseudo/switch.c          |   7 ++-
 plugins/dalvik/v35/instruction.c        |   8 +--
 plugins/pychrysalide/arch/instruction.c |   4 +-
 src/arch/instruction-int.h              |  63 ++++++++++++++++++-
 src/arch/instruction.c                  | 108 ++++++++++++++++++++++++++++----
 src/arch/instruction.h                  |   3 +
 src/common/cpp.h                        |   7 +++
 src/glibext/Makefile.am                 |   1 +
 src/glibext/objhole.h                   |  71 +++++++++++++++++++++
 11 files changed, 253 insertions(+), 23 deletions(-)
 create mode 100644 src/glibext/objhole.h

diff --git a/plugins/arm/v7/instruction.c b/plugins/arm/v7/instruction.c
index 97adddd..1c94887 100644
--- a/plugins/arm/v7/instruction.c
+++ b/plugins/arm/v7/instruction.c
@@ -210,7 +210,7 @@ GArchInstruction *g_armv7_instruction_new(itid_t uid, ARMv7Syntax sid)
 
     result = g_object_new(G_TYPE_ARMV7_INSTRUCTION, NULL);
 
-    G_ARCH_INSTRUCTION(result)->uid = uid;
+    g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(result), uid);
 
     result->sid = sid;
 
diff --git a/plugins/dalvik/pseudo/fill.c b/plugins/dalvik/pseudo/fill.c
index 12382f7..cc8a412 100644
--- a/plugins/dalvik/pseudo/fill.c
+++ b/plugins/dalvik/pseudo/fill.c
@@ -183,7 +183,7 @@ GArchInstruction *g_dalvik_fill_instr_new(uint16_t ident, GDalvikContext *ctx, c
 
     result = g_object_new(G_TYPE_DALVIK_FILL_INSTR, NULL);
 
-    G_ARCH_INSTRUCTION(result)->uid = DPO_FILL_ARRAY_DATA;
+    g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(result), DPO_FILL_ARRAY_DATA);
 
     if (!g_binary_content_read_u16(content, pos, SRE_LITTLE, &result->item_width))
         goto gdfin_bad;
diff --git a/plugins/dalvik/pseudo/switch.c b/plugins/dalvik/pseudo/switch.c
index ea3aa90..f09fe59 100644
--- a/plugins/dalvik/pseudo/switch.c
+++ b/plugins/dalvik/pseudo/switch.c
@@ -193,7 +193,7 @@ GArchInstruction *g_dalvik_switch_instr_new(uint16_t ident, GDalvikContext *ctx,
 
     result = g_object_new(G_TYPE_DALVIK_SWITCH_INSTR, NULL);
 
-    G_ARCH_INSTRUCTION(result)->uid = ident;
+    g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(result), ident);
 
     if (!g_binary_content_read_u16(content, pos, SRE_LITTLE, &result->switch_size))
         goto gdsin_bad;
@@ -237,6 +237,7 @@ GArchInstruction *g_dalvik_switch_instr_new(uint16_t ident, GDalvikContext *ctx,
 static bool g_dalvik_switch_decode_data(GDalvikSwitchInstr *instr, const GBinContent *content, const vmpa2t *pos)
 {
     vmpa2t iter;                            /* Position modifiable         */
+    itid_t uid;                             /* Identifiant unique          */
     int32_t first_key;                      /* Première clef               */
     uint16_t i;                             /* Boucle de parcours          */
 
@@ -245,7 +246,9 @@ static bool g_dalvik_switch_decode_data(GDalvikSwitchInstr *instr, const GBinCon
 
     copy_vmpa(&iter, pos);
 
-    if (G_ARCH_INSTRUCTION(instr)->uid == DPO_PACKED_SWITCH)
+    uid = g_arch_instruction_get_unique_id(G_ARCH_INSTRUCTION(instr));
+
+    if (uid == DPO_PACKED_SWITCH)
     {
         if (!g_binary_content_read_s32(content, &iter, SRE_LITTLE, &first_key))
             goto gdsdd_bad;
diff --git a/plugins/dalvik/v35/instruction.c b/plugins/dalvik/v35/instruction.c
index 28cb0dd..773ec7a 100644
--- a/plugins/dalvik/v35/instruction.c
+++ b/plugins/dalvik/v35/instruction.c
@@ -185,7 +185,7 @@ GArchInstruction *g_dalvik35_instruction_new(itid_t uid)
 
     result = g_object_new(G_TYPE_DALVIK35_INSTRUCTION, NULL);
 
-    G_ARCH_INSTRUCTION(result)->uid = uid;
+    g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(result), uid);
 
     return G_ARCH_INSTRUCTION(result);
 
@@ -232,7 +232,7 @@ static const char *g_dalvik35_instruction_get_keyword(const GDalvik35Instruction
     const char *result;                     /* Désignation à retourner     */
     itid_t uid;                             /* Accès simplifié             */
 
-    uid = G_ARCH_INSTRUCTION(instr)->uid;
+    uid = g_arch_instruction_get_unique_id(G_ARCH_INSTRUCTION(instr));
 
     assert(uid < DOP35_COUNT);
 
@@ -272,7 +272,7 @@ static void g_dalvik35_instruction_call_hook(GDalvik35Instruction *instr, InstrP
 
     base = G_ARCH_INSTRUCTION(instr);
 
-    uid = base->uid;
+    uid = g_arch_instruction_get_unique_id(base);
 
     assert(uid < DOP35_COUNT);
 
@@ -301,7 +301,7 @@ static const char *g_dalvik35_instruction_get_description(const GDalvik35Instruc
     const char *result;                     /* Description à retourner     */
     itid_t uid;                             /* Accès simplifié             */
 
-    uid = G_ARCH_INSTRUCTION(instr)->uid;
+    uid = g_arch_instruction_get_unique_id(G_ARCH_INSTRUCTION(instr));
 
     assert(uid < DOP35_COUNT);
 
diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c
index 1be3edb..757949a 100644
--- a/plugins/pychrysalide/arch/instruction.c
+++ b/plugins/pychrysalide/arch/instruction.c
@@ -407,7 +407,7 @@ static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kw
 
     instr->cached_keyword = strdup(keyword);
 
-    G_ARCH_INSTRUCTION(instr)->uid = uid;
+    g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid);
 
     return 0;
 
@@ -723,7 +723,7 @@ static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unus
 *                                                                             *
 *  Description : Fournit l'identifiant unique pour un ensemble d'instructions.*
 *                                                                             *
-*  Retour      : Identifiant unique par type d'instruction et architecture.   *
+*  Retour      : Identifiant unique par type d'instruction.                   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h
index af897b0..fcb5453 100644
--- a/src/arch/instruction-int.h
+++ b/src/arch/instruction-int.h
@@ -27,6 +27,7 @@
 
 #include "instruction.h"
 #include "../common/array.h"
+#include "../glibext/objhole.h"
 
 
 
@@ -58,6 +59,38 @@ typedef GBufferLine * (* print_instruction_fc) (const GArchInstruction *, GBuffe
 typedef void (* get_instruction_rw_regs_fc) (const GArchInstruction *, GArchRegister ***, size_t *, GArchRegister ***, size_t *);
 
 
+/* Informations glissées dans la structure GObject de GArchInstruction */
+typedef union _instr_obj_extra
+{
+    struct
+    {
+        itid_t uid;                         /* Identifiant unique du type  */
+
+        ArchInstrFlag flags;                /* Informations complémentaires*/
+
+    };
+
+    gint lock;                              /* Gestion d'accès aux fanions */
+
+} instr_obj_extra;
+
+/**
+ * Choix du bit de verrou pour le champ "lock".
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#   define INSTR_EXTRA_LOCK_BIT 31
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+#   define INSTR_EXTRA_LOCK_BIT 0
+
+#else
+
+#   error "Unknown byte order"
+
+#endif
 
 /* Définition générique d'une instruction d'architecture (instance) */
 struct _GArchInstruction
@@ -93,12 +126,38 @@ struct _GArchInstruction
     flat_array_t *from;                     /* Origines des références     */
     flat_array_t *to;                       /* Instructions visées         */
 
-    itid_t uid;                             /* Identifiant unique du type  */
+#if __SIZEOF_INT__ == __SIZEOF_LONG__
 
-    ArchInstrFlag flags;                    /* Informations complémentaires*/
+    /**
+     * L'inclusion des informations suivantes dépend de l'architecture.
+     *
+     * Si la structure GObject possède un trou, on remplit de préférence
+     * ce dernier.
+     */
+
+    instr_obj_extra extra;                  /* Externalisation embarquée   */
+
+#endif
 
 };
 
+/**
+ * Accès aux informations éventuellement déportées.
+ */
+
+#if __SIZEOF_INT__ == __SIZEOF_LONG__
+
+#   define INIT_ARCH_INSTR_EXTRA(ins) ins->extra.lock = 0
+
+#   define GET_ARCH_INSTR_EXTRA(ins) &ins->extra
+
+#else
+
+#   define INIT_ARCH_INSTR_EXTRA(ins) INIT_GOBJECT_EXTRA(G_OBJECT(ins))
+
+#   define GET_ARCH_INSTR_EXTRA(ins) GET_GOBJECT_EXTRA(G_OBJECT(ins), instr_obj_extra)
+
+#endif
 
 /* Définition générique d'une instruction d'architecture (classe) */
 struct _GArchInstructionClass
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index f571330..d3ac97e 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -139,6 +139,8 @@ static void g_arch_instruction_class_init(GArchInstructionClass *klass)
 
 static void g_arch_instruction_init(GArchInstruction *instr)
 {
+    INIT_ARCH_INSTR_EXTRA(instr);
+
     instr->operands = NULL;
 
     instr->from = NULL;
@@ -278,9 +280,20 @@ const char *g_arch_instruction_get_encoding(const GArchInstruction *instr)
 
 bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag)
 {
-    instr->flags |= flag;
+    bool result;                            /* Bilan à retourner           */
+    instr_obj_extra *extra;                 /* Données insérées à modifier */
+
+    extra = GET_ARCH_INSTR_EXTRA(instr);
+
+    g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    extra->flags |= flag;
+
+    result = true;
 
-    return true;
+    g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    return result;
 
 }
 
@@ -301,8 +314,15 @@ bool g_arch_instruction_set_flag(GArchInstruction *instr, ArchInstrFlag flag)
 bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag flag)
 {
     bool result;                            /* Bilan à retourner           */
+    instr_obj_extra *extra;                 /* Données insérées à consulter*/
+
+    extra = GET_ARCH_INSTR_EXTRA(instr);
+
+    g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
 
-    result = (instr->flags & flag);
+    result = (extra->flags & flag);
+
+    g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
 
     return result;
 
@@ -323,7 +343,46 @@ bool g_arch_instruction_has_flag(const GArchInstruction *instr, ArchInstrFlag fl
 
 ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
 {
-    return instr->flags;
+    ArchInstrFlag result;                   /* Fanions à retourner         */
+    instr_obj_extra *extra;                 /* Données insérées à consulter*/
+
+    extra = GET_ARCH_INSTR_EXTRA(instr);
+
+    g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    result = extra->flags;
+
+    g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instruction quelconque à consulter.                  *
+*                uid   = identifiant unique par type d'instruction.           *
+*                                                                             *
+*  Description : Définit l'identifiant unique pour un ensemble d'instructions.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_arch_instruction_set_unique_id(GArchInstruction *instr, itid_t uid)
+{
+    instr_obj_extra *extra;                 /* Données insérées à modifier */
+
+    extra = GET_ARCH_INSTR_EXTRA(instr);
+
+    g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    extra->uid = uid;
+
+    g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
 
 }
 
@@ -343,8 +402,15 @@ ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *instr)
 itid_t g_arch_instruction_get_unique_id(const GArchInstruction *instr)
 {
     itid_t result;                          /* Numéro à retourner          */
+    instr_obj_extra *extra;                 /* Données insérées à consulter*/
+
+    extra = GET_ARCH_INSTR_EXTRA(instr);
 
-    result = instr->uid;
+    g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    result = extra->uid;
+
+    g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
 
     return result;
 
@@ -1409,6 +1475,7 @@ static bool g_arch_instruction_unserialize(GArchInstruction *instr, GAsmStorage
     GArchOperand *op;                       /* Opérande à traiter          */
     instr_link_t link;                      /* Lien vers une instruction   */
     packed_buffer ins_pbuf;                 /* Tampon des données à écrire */
+    instr_obj_extra *extra;                 /* Données insérées à consulter*/
 
     result = unpack_mrange(&instr->range, pbuf);
 
@@ -1489,10 +1556,19 @@ static bool g_arch_instruction_unserialize(GArchInstruction *instr, GAsmStorage
     }
 
     if (result)
-        result = extract_packed_buffer(pbuf, &instr->uid, sizeof(itid_t), true);
+    {
+        extra = GET_ARCH_INSTR_EXTRA(instr);
 
-    if (result)
-        result = extract_packed_buffer(pbuf, &instr->flags, sizeof(ArchInstrFlag), true);
+        g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+        result = extract_packed_buffer(pbuf, &extra->uid, sizeof(itid_t), true);
+
+        if (result)
+            result = extract_packed_buffer(pbuf, &extra->flags, sizeof(ArchInstrFlag), true);
+
+        g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    }
 
     return result;
 
@@ -1561,6 +1637,7 @@ static bool g_arch_instruction_serialize(GArchInstruction *instr, GAsmStorage *s
     off64_t pos;                            /* Position dans le flux       */
     size_t kept;                            /* Nombre de liens conservés   */
     const instr_link_t *link;               /* Lien vers une instruction   */
+    instr_obj_extra *extra;                 /* Données insérées à consulter*/
 
     result = pack_mrange(&instr->range, pbuf);
 
@@ -1661,10 +1738,19 @@ static bool g_arch_instruction_serialize(GArchInstruction *instr, GAsmStorage *s
     }
 
     if (result)
-        result = extend_packed_buffer(pbuf, &instr->uid, sizeof(itid_t), true);
+    {
+        extra = GET_ARCH_INSTR_EXTRA(instr);
 
-    if (result)
-        result = extend_packed_buffer(pbuf, &instr->flags, sizeof(ArchInstrFlag), true);
+        g_bit_lock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+        result = extend_packed_buffer(pbuf, &extra->uid, sizeof(itid_t), true);
+
+        if (result)
+            result = extend_packed_buffer(pbuf, &extra->flags, sizeof(ArchInstrFlag), true);
+
+        g_bit_unlock(&extra->lock, INSTR_EXTRA_LOCK_BIT);
+
+    }
 
     return result;
 
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index af6b03a..6c04acb 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -93,6 +93,9 @@ bool g_arch_instruction_has_flag(const GArchInstruction *, ArchInstrFlag);
 /* Fournit les informations complémentaires d'une instruction. */
 ArchInstrFlag g_arch_instruction_get_flags(const GArchInstruction *);
 
+/* Définit l'identifiant unique pour un ensemble d'instructions. */
+void g_arch_instruction_set_unique_id(GArchInstruction *, itid_t);
+
 /* Fournit l'identifiant unique pour un ensemble d'instructions. */
 itid_t g_arch_instruction_get_unique_id(const GArchInstruction *);
 
diff --git a/src/common/cpp.h b/src/common/cpp.h
index dc0c208..2305b29 100644
--- a/src/common/cpp.h
+++ b/src/common/cpp.h
@@ -47,5 +47,12 @@
 #define SIZE_T_MAXLEN strlen(XSTR(LONG_MAX))
 
 
+/**
+ * Emprunt au noyau Linux (cf. include/linux/bug.h) pour les vérifications à la compilation.
+ */
+
+#define BUILD_BUG_ON(cond) (((void)sizeof(char[1 - 2 * !!(cond)])))
+
+
 
 #endif  /* _COMMON_CPP_H */
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 127f60c..af4f876 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -25,6 +25,7 @@ libglibext_la_SOURCES =					\
 	linegen-int.h						\
 	linegen.h linegen.c					\
 	linesegment.h linesegment.c			\
+	objhole.h							\
 	proto.h								\
 	seq.h seq.c							\
 	signal.h signal.c
diff --git a/src/glibext/objhole.h b/src/glibext/objhole.h
new file mode 100644
index 0000000..184e599
--- /dev/null
+++ b/src/glibext/objhole.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * objhole.h - prototypes pour l'utilisation d'un espace inutilisé dans la structure GObject
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_OBJHOLE_H
+#define _GLIBEXT_OBJHOLE_H
+
+
+#include <glib-object.h>
+
+
+#include "../common/cpp.h"
+
+
+
+/**
+ * Une structure GObject a la définition suivante :
+ *
+ *    struct  _GObject
+ *    {
+ *        GTypeInstance  g_type_instance;
+ *        volatile guint ref_count;
+ *        GData          *qdata;
+ *    };
+ *
+ * L'espace entre les deux derniers champs est exploité ici.
+ */
+
+
+#define INIT_GOBJECT_EXTRA(obj)                                 \
+    do                                                          \
+    {                                                           \
+        guint *___space;                                        \
+        ___space = (((guint *)&obj->ref_count) + 1);            \
+        BUILD_BUG_ON((___space + 1) == (guint *)&obj->qdata);   \
+        *___space = 0;                                          \
+    }                                                           \
+    while (0)
+
+
+#define GET_GOBJECT_EXTRA(obj, tp)                              \
+    ({                                                          \
+        BUILD_BUG_ON(sizeof(tp) > sizeof(guint));               \
+        tp *___result;                                          \
+        ___result = (tp *)(((guint *)&obj->ref_count) + 1);     \
+        BUILD_BUG_ON((___result + 1) == (tp *)&obj->qdata);     \
+        ___result;                                              \
+    })
+
+
+
+#endif  /* _GLIBEXT_OBJHOLE_H */
-- 
cgit v0.11.2-87-g4458