From ae3725eae3c1f2008e6f26b1057d97a6b9050a3c Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 25 Jan 2019 23:13:27 +0100
Subject: Provided API to subclass instructions and operands in Python.

---
 plugins/pychrysalide/arch/instruction.c       | 369 +++++++++++++++++++++++---
 plugins/pychrysalide/arch/operand.c           | 112 +++++++-
 plugins/pychrysalide/arch/operands/register.c |   2 +-
 src/arch/operand.c                            |   5 +
 src/arch/operand.h                            |   3 +
 5 files changed, 445 insertions(+), 46 deletions(-)

diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c
index ce554ee..881c6ff 100644
--- a/plugins/pychrysalide/arch/instruction.c
+++ b/plugins/pychrysalide/arch/instruction.c
@@ -26,10 +26,13 @@
 
 
 #include <assert.h>
+#include <string.h>
 #include <pygobject.h>
 
 
-#include <arch/instruction.h>
+#include <i18n.h>
+#include <arch/instruction-int.h>
+#include <plugins/dt.h>
 
 
 #include "vmpa.h"
@@ -39,17 +42,83 @@
 
 
 
+/* -------------------- INTERFACE INTERNE POUR EXTENSIONS PYTHON -------------------- */
+
+
+/* Définition générique d'une instruction d'architecture (instance) */
+typedef struct _GPyArchInstruction
+{
+    GArchInstruction parent;                /* A laisser en premier        */
+
+    char *cached_keyword;                   /* Conservation de constante   */
+
+} GPyArchInstruction;
+
+
+/* Définition générique d'une instruction d'architecture (classe) */
+typedef struct _GPyArchInstructionClass
+{
+    GArchInstructionClass parent;           /* A laisser en premier        */
+
+} GPyArchInstructionClass;
+
+
+#define G_TYPE_PYARCH_INSTRUCTION            g_pyarch_instruction_get_type()
+#define G_PYARCH_INSTRUCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstruction))
+#define G_IS_PYTHON_INSTRUCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYARCH_INSTRUCTION))
+#define G_PYARCH_INSTRUCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass))
+#define G_IS_PYTHON_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYARCH_INSTRUCTION))
+#define G_PYARCH_INSTRUCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass))
+
+
+/* Indique le type défini pour une instruction d'architecture en Python. */
+GType g_pyarch_instruction_get_type(void);
+
+/* Initialise la classe générique des instructions en Python. */
+static void g_pyarch_instruction_class_init(GPyArchInstructionClass *);
+
+/* Initialise une instance d'opérande d'architecture. */
+static void g_pyarch_instruction_init(GPyArchInstruction *);
+
+/* Supprime toutes les références externes. */
+static void g_pyarch_instruction_dispose(GPyArchInstruction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_pyarch_instruction_finalize(GPyArchInstruction *);
+
+/* Fournit le nom humain de l'instruction manipulée. */
+static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *);
+
+
+
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_arch_instruction_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise la classe générique des instructions. */
+static void py_arch_instruction_init_gclass(GPyArchInstructionClass *, gpointer);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_arch_instruction_init(PyObject *, PyObject *, PyObject *);
+
+
 
 /* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
 
 
+/* Fournit les origines d'une instruction donnée. */
+static PyObject *py_arch_instruction_get_sources(PyObject *, void *);
+
+/* Fournit les destinations d'une instruction donnée. */
+static PyObject *py_arch_instruction_get_destinations(PyObject *, void *);
 
 
 
 /* --------------------- INSTRUCTIONS D'ARCHITECTURES EN PYTHON --------------------- */
 
 
-
 /* Fournit l'identifiant unique pour un ensemble d'instructions. */
 static PyObject *py_arch_instruction_get_unique_id(PyObject *, void *);
 
@@ -59,44 +128,281 @@ static PyObject *py_arch_instruction_get_range(PyObject *, void *);
 /* Définit la localisation d'une instruction. */
 static int py_arch_instruction_set_range(PyObject *, PyObject *, void *);
 
-
-
 /* Fournit le nom humain de l'instruction manipulée. */
 static PyObject *py_arch_instruction_get_keyword(PyObject *, void *);
 
-
-
 /* Fournit tous les opérandes d'une instruction. */
 static PyObject *py_arch_instruction_get_operands(PyObject *, void *);
 
+/* Définit les constantes pour les instructions. */
+static bool py_arch_instruction_define_constants(PyTypeObject *);
 
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                      INTERFACE INTERNE POUR EXTENSIONS PYTHON                      */
+/* ---------------------------------------------------------------------------------- */
 
 
-/* Définit les constantes pour les instructions. */
-static bool py_arch_instruction_define_constants(PyTypeObject *);
+/* Indique le type défini pour une instruction d'architecture en Python. */
+G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION);
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe générique des instructions en Python.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pyarch_instruction_class_init(GPyArchInstructionClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GArchInstructionClass *instr;           /* Encore une autre vision...  */
+
+    object = G_OBJECT_CLASS(klass);
 
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_pyarch_instruction_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_pyarch_instruction_finalize;
 
+    instr = G_ARCH_INSTRUCTION_CLASS(klass);
+
+    instr->get_keyword = (get_instruction_keyword_fc)g_pyarch_instruction_get_keyword;
+
+}
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instance à initialiser.                              *
+*                                                                             *
+*  Description : Initialise une instance d'instruction d'architecture.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pyarch_instruction_init(GPyArchInstruction *instr)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instance d'objet GLib à traiter.                     *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pyarch_instruction_dispose(GPyArchInstruction *instr)
+{
+    G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->dispose(G_OBJECT(instr));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instance d'objet GLib à traiter.                     *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_pyarch_instruction_finalize(GPyArchInstruction *instr)
+{
+    if (instr->cached_keyword)
+        free(instr->cached_keyword);
+
+    G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->finalize(G_OBJECT(instr));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instruction d'assemblage à consulter.                *
+*                                                                             *
+*  Description : Fournit le nom humain de l'instruction manipulée.            *
+*                                                                             *
+*  Retour      : Mot clef de bas niveau.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *instr)
+{
+    const char *result;                     /* Désignation à retourner     */
+
+    result = instr->cached_keyword;
+
+    return result;
+
+}
+
 
 /* ---------------------------------------------------------------------------------- */
-/*                     DEFINITION DES LIAISONS ENTRE INSTRUCTIONS                     */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
 /* ---------------------------------------------------------------------------------- */
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type du nouvel objet à mettre en place.               *
+*                args = éventuelle liste d'arguments.                         *
+*                kwds = éventuel dictionnaire de valeurs mises à disposition. *
+*                                                                             *
+*  Description : Accompagne la création d'une instance dérivée en Python.     *
+*                                                                             *
+*  Retour      : Nouvel objet Python mis en place ou NULL en cas d'échec.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
+static PyObject *py_arch_instruction_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result;                       /* Objet à retourner           */
+    PyTypeObject *base;                     /* Type de base à dériver      */
+    bool first_time;                        /* Evite les multiples passages*/
+    GType gtype;                            /* Nouveau type de processeur  */
+    bool status;                            /* Bilan d'un enregistrement   */
 
-/* Fournit les origines d'une instruction donnée. */
-static PyObject *py_arch_instruction_get_sources(PyObject *, void *);
+    /* Validations diverses */
 
-/* Fournit les destinations d'une instruction donnée. */
-static PyObject *py_arch_instruction_get_destinations(PyObject *, void *);
+    base = get_python_arch_instruction_type();
+
+    if (type == base)
+    {
+        result = NULL;
+        PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
+        goto exit;
+    }
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_PYARCH_INSTRUCTION, type->tp_name,
+                               (GClassInitFunc)py_arch_instruction_init_gclass, NULL, NULL);
+
+    if (first_time)
+    {
+        status = register_class_for_dynamic_pygobject(gtype, type, base);
+
+        if (!status)
+        {
+            result = NULL;
+            goto exit;
+        }
+
+    }
+
+    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class  = classe à initialiser.                               *
+*                unused = données non utilisées ici.                          *
+*                                                                             *
+*  Description : Initialise la classe générique des instructions.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_arch_instruction_init_gclass(GPyArchInstructionClass *class, gpointer unused)
+{
+    /// ....
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
+*                args = arguments fournis à l'appel.                          *
+*                kwds = arguments de type key=val fournis.                    *
+*                                                                             *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
+*                                                                             *
+*  Retour      : 0.                                                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    unsigned short int uid;                 /* Indentifiant unique de type */
+    const char *keyword;                    /* Désignation d'instruction   */
+    int ret;                                /* Bilan de lecture des args.  */
+    PyObject *new_kwds;                     /* Nouveau dictionnaire épuré  */
+    GPyArchInstruction *instr;              /* Instruction à manipuler     */
+
+    static char *kwlist[] = { "uid", "keyword", NULL };
+
+    /* Récupération des paramètres */
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword);
+    if (!ret) return -1;
+
+    /* Initialisation d'un objet GLib */
+
+    new_kwds = PyDict_New();
+
+    ret = PyGObject_Type.tp_init(self, args, new_kwds);
+
+    Py_DECREF(new_kwds);
+
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
 
+    instr = G_PYARCH_INSTRUCTION(pygobject_get(self));
 
+    instr->cached_keyword = strdup(keyword);
+
+    G_ARCH_INSTRUCTION(instr)->uid = uid;
+
+    return 0;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                     DEFINITION DES LIAISONS ENTRE INSTRUCTIONS                     */
+/* ---------------------------------------------------------------------------------- */
 
 
 /******************************************************************************
@@ -218,13 +524,9 @@ static PyObject *py_arch_instruction_get_destinations(PyObject *self, void *unus
 
 
 
-
-
-
-
-
-
-
+/* ---------------------------------------------------------------------------------- */
+/*                       INSTRUCTIONS D'ARCHITECTURES EN PYTHON                       */
+/* ---------------------------------------------------------------------------------- */
 
 
 /******************************************************************************
@@ -319,11 +621,6 @@ static int py_arch_instruction_set_range(PyObject *self, PyObject *value, void *
 }
 
 
-
-
-
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self   = classe représentant une instruction.                *
@@ -353,9 +650,6 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *self, void *unused)
 }
 
 
-
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self   = objet représentant une instruction.                 *
@@ -413,18 +707,6 @@ static PyObject *py_arch_instruction_get_operands(PyObject *self, void *unused)
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
@@ -518,6 +800,9 @@ PyTypeObject *get_python_arch_instruction_type(void)
         .tp_methods     = py_arch_instruction_methods,
         .tp_getset      = py_arch_instruction_getseters,
 
+        .tp_init        = py_arch_instruction_init,
+        .tp_new         = py_arch_instruction_new,
+
     };
 
     return &py_arch_instruction_type;
@@ -547,8 +832,6 @@ bool ensure_python_arch_instruction_is_registered(void)
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
     {
-        APPLY_ABSTRACT_FLAG(type);
-
         module = get_access_to_python_module("pychrysalide.arch");
 
         dict = PyModule_GetDict(module);
@@ -556,7 +839,7 @@ bool ensure_python_arch_instruction_is_registered(void)
         if (!ensure_python_line_generator_is_registered())
             return false;
 
-        if (!_register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, type,
+        if (!_register_class_for_pygobject(dict, G_TYPE_PYARCH_INSTRUCTION, type,
                                            &PyGObject_Type, get_python_line_generator_type(), NULL))
             return false;
 
diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c
index e464eac..4630b3a 100644
--- a/plugins/pychrysalide/arch/operand.c
+++ b/plugins/pychrysalide/arch/operand.c
@@ -29,6 +29,7 @@
 
 
 #include <arch/operand.h>
+#include <plugins/dt.h>
 
 
 #include "../access.h"
@@ -36,6 +37,113 @@
 
 
 
+/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_arch_operand_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise la classe des descriptions de fichier binaire. */
+static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer);
+
+
+
+/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          GLUE POUR CREATION DEPUIS PYTHON                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type du nouvel objet à mettre en place.               *
+*                args = éventuelle liste d'arguments.                         *
+*                kwds = éventuel dictionnaire de valeurs mises à disposition. *
+*                                                                             *
+*  Description : Accompagne la création d'une instance dérivée en Python.     *
+*                                                                             *
+*  Retour      : Nouvel objet Python mis en place ou NULL en cas d'échec.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result;                       /* Objet à retourner           */
+    PyTypeObject *base;                     /* Type de base à dériver      */
+    bool first_time;                        /* Evite les multiples passages*/
+    GType gtype;                            /* Nouveau type de processeur  */
+    bool status;                            /* Bilan d'un enregistrement   */
+
+    /* Validations diverses */
+
+    base = get_python_arch_operand_type();
+
+    if (type == base)
+        goto simple_way;
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_ARCH_OPERAND, type->tp_name,
+                               (GClassInitFunc)py_arch_operand_init_gclass, NULL, NULL);
+
+    if (first_time)
+    {
+        status = register_class_for_dynamic_pygobject(gtype, type, base);
+
+        if (!status)
+        {
+            result = NULL;
+            goto exit;
+        }
+
+    }
+
+    /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */
+
+ simple_way:
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class  = classe à initialiser.                               *
+*                unused = données non utilisées ici.                          *
+*                                                                             *
+*  Description : Initialise la classe des descriptions de fichier binaire.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unused)
+{
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          DEFINITION D'OPERANDE QUELCONQUE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : -                                                            *
@@ -72,6 +180,8 @@ PyTypeObject *get_python_arch_operand_type(void)
         .tp_methods     = py_arch_operand_methods,
         .tp_getset      = py_arch_operand_getseters,
 
+        .tp_new         = py_arch_operand_new,
+
     };
 
     return &py_arch_operand_type;
@@ -101,8 +211,6 @@ bool ensure_python_arch_operand_is_registered(void)
 
     if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
     {
-        APPLY_ABSTRACT_FLAG(type);
-
         module = get_access_to_python_module("pychrysalide.arch");
 
         dict = PyModule_GetDict(module);
diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c
index 8144af0..3e77c9b 100644
--- a/plugins/pychrysalide/arch/operands/register.c
+++ b/plugins/pychrysalide/arch/operands/register.c
@@ -50,7 +50,7 @@ static PyObject *py_register_operand_new(PyTypeObject *, PyObject *, PyObject *)
 static void py_register_operand_init_gclass(GRegisterOperandClass *, gpointer);
 
 /* Initialise une instance sur la base du dérivé de GObject. */
-static int py_register_operand_init(PyObject *self, PyObject *args, PyObject *kwds);
+static int py_register_operand_init(PyObject *, PyObject *, PyObject *);
 
 
 
diff --git a/src/arch/operand.c b/src/arch/operand.c
index 07a93ab..5936979 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -36,6 +36,11 @@
 
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                          DEFINITION D'OPERANDE QUELCONQUE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
 /* Initialise la classe générique des opérandes. */
 static void g_arch_operand_class_init(GArchOperandClass *);
 
diff --git a/src/arch/operand.h b/src/arch/operand.h
index 9a36f3d..a881a91 100644
--- a/src/arch/operand.h
+++ b/src/arch/operand.h
@@ -34,6 +34,9 @@
 
 
 
+/* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */
+
+
 /* Depuis "../analysis/binary.h" : description de fichier binaire */
 typedef struct _GLoadedBinary GLoadedBinary;
 
-- 
cgit v0.11.2-87-g4458