From ae3725eae3c1f2008e6f26b1057d97a6b9050a3c Mon Sep 17 00:00:00 2001 From: Cyrille Bagard 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 +#include #include -#include +#include +#include +#include #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 +#include #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