From 340cbdbc4abedd060f3eb6745cd44e33ed19b93c Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 15 Aug 2019 10:01:39 +0200 Subject: Introduced binary symbol subclassing from Python. --- plugins/pychrysalide/format/symbol.c | 236 +++++++++++++++++++++++++++++------ plugins/pychrysalide/helpers.c | 31 +++++ plugins/pychrysalide/helpers.h | 3 + tests/format/symbol.py | 29 +++++ 4 files changed, 264 insertions(+), 35 deletions(-) diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c index 86a321c..962c627 100644 --- a/plugins/pychrysalide/format/symbol.c +++ b/plugins/pychrysalide/format/symbol.c @@ -27,13 +27,15 @@ #include #include +#include #include #include -#include +#include +#include #include "constants.h" @@ -47,12 +49,29 @@ -/* Effectue une comparaison avec un objet Python 'BinSymbol'. */ -static PyObject *py_binary_symbol_richcompare(PyObject *, PyObject *, int); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + -/* Crée un nouvel objet Python de type 'BinSymbol'. */ +/* Accompagne la création d'une instance dérivée en Python. */ static PyObject *py_binary_symbol_new(PyTypeObject *, PyObject *, PyObject *); +/* Initialise la classe des symboles d'exécutables. */ +static void py_binary_symbol_init_gclass(GBinSymbolClass *, gpointer); + +/* Fournit une étiquette pour viser un symbole. */ +static char *g_binary_symbol_get_label_wrapper(const GBinSymbol *); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_binary_symbol_init(PyObject *, PyObject *, PyObject *); + + + +/* --------------------- FONCTIONNALITES BASIQUES POUR SYMBOLES --------------------- */ + + +/* Effectue une comparaison avec un objet Python 'BinSymbol'. */ +static PyObject *py_binary_symbol_richcompare(PyObject *, PyObject *, int); + /* Fournit l'emplacement où se situe un symbole. */ static PyObject *py_binary_symbol_get_range(PyObject *, void *); @@ -79,45 +98,129 @@ static int py_binary_symbol_set_label(PyObject *, PyObject *, void *); +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : a = premier object Python à consulter. * -* b = second object Python à consulter. * -* op = type de comparaison menée. * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * * * -* Description : Effectue une comparaison avec un objet Python 'BinSymbol'. * +* Description : Accompagne la création d'une instance dérivée en Python. * * * -* Retour : Bilan de l'opération. * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_binary_symbol_richcompare(PyObject *a, PyObject *b, int op) +static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *result; /* Bilan à retourner */ - int ret; /* Bilan de lecture des args. */ - const GBinSymbol *sym_a; /* Premier élément à traiter */ - const GBinSymbol *sym_b; /* Second élément à traiter */ - int status; /* Résultat d'une comparaison */ + 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 */ - ret = PyObject_IsInstance(b, (PyObject *)get_python_binary_symbol_type()); - if (!ret) + /* Validations diverses */ + + base = get_python_binary_symbol_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_BIN_SYMBOL, type->tp_name, + (GClassInitFunc)py_binary_symbol_init_gclass, NULL, NULL); + + if (first_time) { - result = Py_NotImplemented; - goto cmp_done; + status = register_class_for_dynamic_pygobject(gtype, type, base); + + if (!status) + { + result = NULL; + goto exit; + } + } - sym_a = G_BIN_SYMBOL(pygobject_get(a)); - sym_b = G_BIN_SYMBOL(pygobject_get(b)); + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - status = g_binary_symbol_cmp(&sym_a, &sym_b); + simple_way: - result = status_to_rich_cmp_state(status, op); + result = PyType_GenericNew(type, args, kwds); - cmp_done: + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe des symboles d'exécutables. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_binary_symbol_init_gclass(GBinSymbolClass *class, gpointer unused) +{ + class->get_label = g_binary_symbol_get_label_wrapper; + +} - Py_INCREF(result); + +/****************************************************************************** +* * +* Paramètres : symbol = symbole à venir consulter. * +* * +* Description : Fournit une étiquette pour viser un symbole. * +* * +* Retour : Chaîne de caractères renvoyant au symbole. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) +{ + char *result; /* Etiquette à retourner */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + + result = NULL; + + pyobj = pygobject_new(G_OBJECT(symbol)); + + if (has_python_method(pyobj, "_get_label")) + { + pyret = run_python_method(pyobj, "_get_label", NULL); + if (pyret == NULL) goto exit; + + if (PyUnicode_Check(pyret)) + result = strdup(PyUnicode_DATA(pyret)); + + Py_DECREF(pyret); + + } + + exit: + + Py_DECREF(pyobj); return result; @@ -126,21 +229,20 @@ static PyObject *py_binary_symbol_richcompare(PyObject *a, PyObject *b, int op) /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'BinSymbol'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_binary_symbol_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Bilan à retourner */ SymbolType stype; /* Type prévu pour le symbole */ mrange_t range; /* Version native d'un espace */ int ret; /* Bilan de lecture des args. */ @@ -157,20 +259,82 @@ static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObje "\n" \ "Where stype is a pychrysalide.format.BinSymbol.SymbolType value, and" \ " range a memory space defined by pychrysalide.arch.mrange." \ + "\n" \ + "The following special method can be overridden:\n" \ + "* _get_label(self): provides a default label for the symbol." + + /* Récupération des paramètres */ ret = PyArg_ParseTuple(args, "kO&", &stype, convert_any_to_mrange, &range); - if (!ret) return NULL; + if (!ret) return -1; if (stype >= STP_COUNT) { PyErr_SetString(PyExc_ValueError, _("Invalid type of symbol.")); - return NULL; + return -1; } - symbol = g_binary_symbol_new(&range, stype); + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + symbol = G_BIN_SYMBOL(pygobject_get(self)); + + g_binary_symbol_set_range(symbol, &range); + g_binary_symbol_set_stype(symbol, stype); + + return 0; + +} + + +/* ---------------------------------------------------------------------------------- */ +/* FONCTIONNALITES BASIQUES POUR SYMBOLES */ +/* ---------------------------------------------------------------------------------- */ - result = pygobject_new(G_OBJECT(symbol)); - g_object_unref(symbol); + +/****************************************************************************** +* * +* Paramètres : a = premier object Python à consulter. * +* b = second object Python à consulter. * +* op = type de comparaison menée. * +* * +* Description : Effectue une comparaison avec un objet Python 'BinSymbol'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_symbol_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + int ret; /* Bilan de lecture des args. */ + const GBinSymbol *sym_a; /* Premier élément à traiter */ + const GBinSymbol *sym_b; /* Second élément à traiter */ + int status; /* Résultat d'une comparaison */ + + ret = PyObject_IsInstance(b, (PyObject *)get_python_binary_symbol_type()); + if (!ret) + { + result = Py_NotImplemented; + goto cmp_done; + } + + sym_a = G_BIN_SYMBOL(pygobject_get(a)); + sym_b = G_BIN_SYMBOL(pygobject_get(b)); + + status = g_binary_symbol_cmp(&sym_a, &sym_b); + + result = status_to_rich_cmp_state(status, op); + + cmp_done: + + Py_INCREF(result); return result; @@ -507,6 +671,8 @@ PyTypeObject *get_python_binary_symbol_type(void) .tp_methods = py_bin_symbol_methods, .tp_getset = py_bin_symbol_getseters, + + .tp_init = py_binary_symbol_init, .tp_new = py_binary_symbol_new }; diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 6e13d3c..59bcd45 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -941,6 +941,37 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp } +/****************************************************************************** +* * +* Paramètres : self = objet Python/GObject à initialiser. * +* * +* Description : Fait suivre à la partie GObject une initialisation nouvelle. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int forward_pygobjet_init(PyObject *self) +{ + bool result; /* Bilan à retourner */ + PyObject *new_args; /* Nouveaux arguments épurés */ + PyObject *new_kwds; /* Nouveau dictionnaire épuré */ + + new_args = PyTuple_New(0); + new_kwds = PyDict_New(); + + result = PyGObject_Type.tp_init(self, new_args, new_kwds); + + Py_DECREF(new_kwds); + Py_DECREF(new_args); + + return result; + +} + + /* ---------------------------------------------------------------------------------- */ /* TRANSFERT DES VALEURS CONSTANTES */ diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index e2ebfbc..8c7db0b 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -154,6 +154,9 @@ bool register_interface_for_pygobject(PyObject *, GType, PyTypeObject *); /* Enregistre un type Python dérivant d'un type GLib dynamique. */ bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *); +/* Fait suivre à la partie GObject une initialisation nouvelle. */ +int forward_pygobjet_init(PyObject *); + /* ----------------------- TRANSFERT DES VALEURS CONSTANTES ------------------------- */ diff --git a/tests/format/symbol.py b/tests/format/symbol.py index 5e0ba10..6cffe57 100644 --- a/tests/format/symbol.py +++ b/tests/format/symbol.py @@ -84,3 +84,32 @@ class TestBinarySymbols(ChrysalideTestCase): self.assertTrue(symbol1 < symbol2) self.assertTrue(symbol0 == symbol2) + + + def testSymbolSubclassing(self): + """Verify the symbol subclassing is working.""" + + class MySymbol(BinSymbol): + def _get_label(self): + return 'AAA' + + saddr = vmpa(0x100, vmpa.VMPA_NO_VIRTUAL) + srange = mrange(saddr, 0x3) + symbol = MySymbol(BinSymbol.SymbolType.ENTRY_POINT, srange) + + self.assertEqual(symbol.label, 'AAA') + + symbol.label = 'BBB' + + self.assertEqual(symbol.label, 'BBB') + + class MyOtherSymbol(BinSymbol): + pass + + other = MyOtherSymbol(BinSymbol.SymbolType.ENTRY_POINT, srange) + + self.assertEqual(other.label, None) + + other.label = 'CCC' + + self.assertEqual(other.label, 'CCC') -- cgit v0.11.2-87-g4458