From 8f557031ec362c4b2e85724f6bc392086cefadea Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 31 Jan 2019 08:44:01 +0100
Subject: Created Python bindings for undefined instructions.

---
 plugins/pychrysalide/arch/Makefile.am     |   1 +
 plugins/pychrysalide/arch/module.c        |   2 +
 plugins/pychrysalide/arch/undefined.c     | 367 ++++++++++++++++++++++++++++++
 plugins/pychrysalide/arch/undefined.h     |  45 ++++
 plugins/pychrysalide/glibext/binportion.c |   2 +-
 src/arch/Makefile.am                      |   1 +
 src/arch/undefined-int.h                  |  51 +++++
 src/arch/undefined.c                      |  19 +-
 src/arch/undefined.h                      |   1 -
 9 files changed, 469 insertions(+), 20 deletions(-)
 create mode 100644 plugins/pychrysalide/arch/undefined.c
 create mode 100644 plugins/pychrysalide/arch/undefined.h
 create mode 100644 src/arch/undefined-int.h

diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am
index b47bf24..b26727d 100644
--- a/plugins/pychrysalide/arch/Makefile.am
+++ b/plugins/pychrysalide/arch/Makefile.am
@@ -13,6 +13,7 @@ libpychrysaarch_la_SOURCES =			\
 	raw.h raw.c							\
 	register.h register.c				\
 	targetableop.h targetableop.c		\
+	undefined.h undefined.c				\
 	vmpa.h vmpa.c
 
 libpychrysaarch_la_LIBADD =				\
diff --git a/plugins/pychrysalide/arch/module.c b/plugins/pychrysalide/arch/module.c
index d412ddc..cacc167 100644
--- a/plugins/pychrysalide/arch/module.c
+++ b/plugins/pychrysalide/arch/module.c
@@ -42,6 +42,7 @@
 #include "raw.h"
 #include "register.h"
 #include "targetableop.h"
+#include "undefined.h"
 #include "vmpa.h"
 #include "operands/module.h"
 #include "../helpers.h"
@@ -178,6 +179,7 @@ bool populate_arch_module(void)
     if (result) result = ensure_python_raw_instruction_is_registered();
     if (result) result = ensure_python_arch_register_is_registered();
     if (result) result = ensure_python_targetable_operand_is_registered();
+    if (result) result = ensure_python_undefined_instruction_is_registered();
     if (result) result = ensure_python_vmpa_is_registered();
     if (result) result = ensure_python_mrange_is_registered();
 
diff --git a/plugins/pychrysalide/arch/undefined.c b/plugins/pychrysalide/arch/undefined.c
new file mode 100644
index 0000000..4d10385
--- /dev/null
+++ b/plugins/pychrysalide/arch/undefined.c
@@ -0,0 +1,367 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * undefined.c - équivalent Python du fichier "arch/undefined.h"
+ *
+ * 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "undefined.h"
+
+
+#include <pygobject.h>
+
+
+#include <i18n.h>
+#include <arch/undefined-int.h>
+#include <plugins/dt.h>
+
+
+#include "instruction.h"
+#include "../access.h"
+#include "../helpers.h"
+
+
+
+/* Accompagne la création d'une instance dérivée en Python. */
+static PyObject *py_undef_instruction_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_undef_instruction_init(PyObject *, PyObject *, PyObject *);
+
+/* Indique le type de conséquences réél de l'instruction. */
+static PyObject *py_undef_instruction_get_status(PyObject *, void *);
+
+/* Définit les constantes pour les instructions non définies. */
+static bool py_undefined_instruction_define_constants(PyTypeObject *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  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_undef_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   */
+
+    /* Validations diverses */
+
+    base = get_python_undefined_instruction_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_UNDEF_INSTRUCTION, type->tp_name, NULL, 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  : 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_undef_instruction_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    unsigned long status;                   /* Conséquence pour l'instruct°*/
+    int ret;                                /* Bilan de lecture des args.  */
+    PyObject *new_args;                     /* Nouveaux arguments épurés   */
+    PyObject *new_kwds;                     /* Nouveau dictionnaire épuré  */
+    GUndefInstruction *instr;               /* Instruction à manipuler     */
+
+    static char *kwlist[] = { "status", NULL };
+
+    /* Récupération des paramètres */
+
+    ret = PyArg_ParseTupleAndKeywords(args, kwds, "k", kwlist, &status);
+    if (!ret) return -1;
+
+    /* Initialisation d'un objet GLib */
+
+    new_args = PyTuple_New(0);
+    new_kwds = PyDict_New();
+
+    ret = PyGObject_Type.tp_init(self, new_args, new_kwds);
+
+    Py_DECREF(new_kwds);
+    Py_DECREF(new_args);
+
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    instr = G_UNDEF_INSTRUCTION(pygobject_get(self));
+
+    instr->status = status;
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self    = classe représentant une instruction.               *
+*                closure = adresse non utilisée ici.                          *
+*                                                                             *
+*  Description : Indique le type de conséquences réél de l'instruction.       *
+*                                                                             *
+*  Retour      : Etat réel du CPU après l'exécution de l'instruction.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_undef_instruction_get_status(PyObject *self, void *closure)
+{
+    PyObject *result;                       /* Conversion à retourner      */
+    GUndefInstruction *instr;               /* Version native              */
+    InstrBehaviorStatus status;             /* Etat de la définition       */
+
+    instr = G_UNDEF_INSTRUCTION(pygobject_get(self));
+
+    status = g_undef_instruction_get_status(instr);
+
+    result = PyLong_FromLong(status);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : obj_type = type dont le dictionnaire est à compléter.        *
+*                                                                             *
+*  Description : Définit les constantes pour les instructions non définies.   *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_undefined_instruction_define_constants(PyTypeObject *obj_type)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_RAW);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_CODE);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DATA);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DATA_RO);
+    if (result) result = PyDict_AddStringMacro(obj_type, BPC_DISASS_ERROR);
+
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_NONE);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_READ);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_WRITE);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_EXEC);
+    if (result) result = PyDict_AddULongMacro(obj_type, PAC_ALL);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit un accès à une définition de type à diffuser.        *
+*                                                                             *
+*  Retour      : Définition d'objet pour Python.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyTypeObject *get_python_undefined_instruction_type(void)
+{
+    static PyMethodDef py_undefined_instruction_methods[] = {
+        { NULL }
+    };
+
+    static PyGetSetDef py_undefined_instruction_getseters[] = {
+        {
+            "status", py_undef_instruction_get_status, NULL,
+            "Consequence carried by the undefined instruction.", NULL
+        },
+        { NULL }
+    };
+
+    static PyTypeObject py_undefined_instruction_type = {
+
+        PyVarObject_HEAD_INIT(NULL, 0)
+
+        .tp_name        = "pychrysalide.arch.UndefInstruction",
+        .tp_basicsize   = sizeof(PyGObject),
+
+        .tp_flags       = Py_TPFLAGS_DEFAULT,
+
+        .tp_doc         = "PyChrysalide undefined instruction for a all architectures.",
+
+        .tp_methods     = py_undefined_instruction_methods,
+        .tp_getset      = py_undefined_instruction_getseters,
+
+        .tp_init        = py_undef_instruction_init,
+        .tp_new         = py_undef_instruction_new,
+
+    };
+
+    return &py_undefined_instruction_type;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
+*                                                                             *
+*  Description : Prend en charge l'objet 'pychrysalide.arch.ArchInstruction'. *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ensure_python_undefined_instruction_is_registered(void)
+{
+    PyTypeObject *type;                     /* Type Python 'UndefinedInstruction'*/
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
+
+    type = get_python_undefined_instruction_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.arch");
+
+        dict = PyModule_GetDict(module);
+
+        if (!ensure_python_arch_instruction_is_registered())
+            return false;
+
+        if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type, get_python_arch_instruction_type()))
+            return false;
+
+        if (!py_undefined_instruction_define_constants(type))
+            return false;
+
+    }
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en instruction non définie.               *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_undefined_instruction(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_undefined_instruction_type());
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to undefined instruction");
+            break;
+
+        case 1:
+            *((GUndefInstruction **)dst) = G_UNDEF_INSTRUCTION(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/arch/undefined.h b/plugins/pychrysalide/arch/undefined.h
new file mode 100644
index 0000000..814f00c
--- /dev/null
+++ b/plugins/pychrysalide/arch/undefined.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * undefined.h - prototypes pour l'équivalent Python du fichier "arch/undefined.h"
+ *
+ * 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _PLUGINS_PYCHRYSALIDE_ARCH_UNDEFINED_H
+#define _PLUGINS_PYCHRYSALIDE_ARCH_UNDEFINED_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_undefined_instruction_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.arch.UndefinedInstruction'. */
+bool ensure_python_undefined_instruction_is_registered(void);
+
+/* Tente de convertir en instruction non définie. */
+int convert_to_undefined_instruction(PyObject *, void *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_ARCH_UNDEFINED_H */
diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c
index 9f719cb..9ecc1eb 100644
--- a/plugins/pychrysalide/glibext/binportion.c
+++ b/plugins/pychrysalide/glibext/binportion.c
@@ -158,8 +158,8 @@ static int py_bin_portion_init(PyObject *self, PyObject *args, PyObject *kwds)
     const char *code;                       /* Identifiant de couleur      */
     vmpa2t addr;                            /* Emplacement de portion      */
     unsigned long long size;                /* Taille de la portion        */
-    PyObject *new_args;                     /* Nouveaux arguments épurés   */
     int ret;                                /* Bilan de lecture des args.  */
+    PyObject *new_args;                     /* Nouveaux arguments épurés   */
     PyObject *new_kwds;                     /* Nouveau dictionnaire épuré  */
     GBinPortion *portion;                   /* Portion à manipuler         */
 
diff --git a/src/arch/Makefile.am b/src/arch/Makefile.am
index ce5db57..c83dd0c 100644
--- a/src/arch/Makefile.am
+++ b/src/arch/Makefile.am
@@ -26,6 +26,7 @@ libarch_la_SOURCES =					\
 	target.h target.c					\
 	targetableop-int.h					\
 	targetableop.h targetableop.c		\
+	undefined-int.h						\
 	undefined.h undefined.c				\
 	vmpa.h vmpa.c
 
diff --git a/src/arch/undefined-int.h b/src/arch/undefined-int.h
new file mode 100644
index 0000000..2f01c4a
--- /dev/null
+++ b/src/arch/undefined-int.h
@@ -0,0 +1,51 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * undefined-int.h - prototypes pour la définition générique interne des instructions au comportement non défini
+ *
+ * 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ARCH_UNDEFINED_INT_H
+#define _ARCH_UNDEFINED_INT_H
+
+
+#include "undefined.h"
+#include "instruction-int.h"
+
+
+
+/* Définition générique d'une instruction au comportement non défini (instance) */
+struct _GUndefInstruction
+{
+    GArchInstruction parent;                /* A laisser en premier        */
+
+    InstrBehaviorStatus status;             /* Conséquences réelles        */
+
+};
+
+/* Définition générique d'une instruction au comportement non défini (classe) */
+struct _GUndefInstructionClass
+{
+    GArchInstructionClass parent;           /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _ARCH_UNDEFINED_INT_H */
diff --git a/src/arch/undefined.c b/src/arch/undefined.c
index 680e4f4..b569eb4 100644
--- a/src/arch/undefined.c
+++ b/src/arch/undefined.c
@@ -30,27 +30,10 @@
 #include <i18n.h>
 
 
-#include "instruction-int.h"
+#include "undefined-int.h"
 
 
 
-/* Définition générique d'une instruction au comportement non défini (instance) */
-struct _GUndefInstruction
-{
-    GArchInstruction parent;                /* A laisser en premier        */
-
-    InstrBehaviorStatus status;             /* Conséquences réelles        */
-
-};
-
-/* Définition générique d'une instruction au comportement non défini (classe) */
-struct _GUndefInstructionClass
-{
-    GArchInstructionClass parent;           /* A laisser en premier        */
-
-};
-
-
 /* Initialise la classe des instructions non définies. */
 static void g_undef_instruction_class_init(GUndefInstructionClass *);
 
diff --git a/src/arch/undefined.h b/src/arch/undefined.h
index 74db9fa..605da0b 100644
--- a/src/arch/undefined.h
+++ b/src/arch/undefined.h
@@ -55,7 +55,6 @@ typedef enum _InstrBehaviorStatus
     IBS_UNDEFINED,
     IBS_UNPREDICTABLE,
 
-
 } InstrBehaviorStatus;
 
 
-- 
cgit v0.11.2-87-g4458