diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2020-05-03 18:15:46 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2020-05-03 18:15:46 (GMT) |
commit | 78da8b1ad594ca24292eb0f047698bc952b7b961 (patch) | |
tree | 1e461944f2a5d9f6b61eb6ca31048021580596cd /plugins/pychrysalide/arch/operand.c | |
parent | 85ddac0558313b5d3fbd9428ae3e9614f16d514d (diff) |
Defined the missing features required to build operands from Python.
Diffstat (limited to 'plugins/pychrysalide/arch/operand.c')
-rw-r--r-- | plugins/pychrysalide/arch/operand.c | 281 |
1 files changed, 274 insertions, 7 deletions
diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c index e3c6dcf..f14a6cc 100644 --- a/plugins/pychrysalide/arch/operand.c +++ b/plugins/pychrysalide/arch/operand.c @@ -28,7 +28,8 @@ #include <pygobject.h> -#include <arch/operand.h> +#include <i18n.h> +#include <arch/operand-int.h> #include <plugins/dt.h> @@ -43,14 +44,26 @@ /* 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. */ +/* Initialise la classe générique des opérandes. */ static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer); +/* Compare un opérande avec un autre. */ +static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *); + +/* Traduit un opérande en version humainement lisible. */ +static void py_arch_operand_print_wrapper(const GArchOperand *, GBufferLine *); + +/* Construit un petit résumé concis de l'opérande. */ +static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const GLoadedBinary *); + /* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ +/* Effectue une comparaison avec un objet Python 'ArchOperand'. */ +static PyObject *py_arch_operand_richcompare(PyObject *, PyObject *, int); + /* ---------------------------------------------------------------------------------- */ @@ -80,12 +93,31 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec GType gtype; /* Nouveau type de processeur */ bool status; /* Bilan d'un enregistrement */ +#define ARCH_OPERAND_DOC \ + "The ArchOperand object aims to get subclassed to create" \ + " operands of any kind for new architectures.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " no particular argument.\n" \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.arch.ArchRegister.__cmp__();\n" \ + "* pychrysalide.arch.ArchRegister._print();\n" \ + "* pychrysalide.arch.ArchRegister._build_tooltip().\n" \ + "\n" \ + "Chrysalide creates an internal glue to provide rich comparisons" \ + " for operands based on the old-style *__cmp__* function." + /* Validations diverses */ base = get_python_arch_operand_type(); if (type == base) - goto simple_way; + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } /* Mise en place d'un type dédié */ @@ -108,8 +140,6 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - simple_way: - result = PyType_GenericNew(type, args, kwds); exit: @@ -124,7 +154,7 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec * Paramètres : class = classe à initialiser. * * unused = données non utilisées ici. * * * -* Description : Initialise la classe des descriptions de fichier binaire. * +* Description : Initialise la classe générique des opérandes. * * * * Retour : - * * * @@ -134,6 +164,193 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unused) { + class->compare = py_arch_operand___cmp___wrapper; + class->print = py_arch_operand_print_wrapper; + class->build_tooltip = py_arch_operand_build_tooltip_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* * +* Description : Compare un opérande avec un autre. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOperand *b) +{ + int result; /* Empreinte à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define ARCH_OPERAND_CMP_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + __cmp__, "$self, other, /", \ + METH_VARARGS, \ + "Abstract method used to compare the operand with another" \ + " one. This second object is always an" \ + " pychrysalide.arch.ArchOperand instance.\n" \ + "\n" \ + " This is the Python old-style comparison method, but" \ + " Chrysalide provides a glue to automatically build a rich" \ + " version of this function." \ +) + + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(a)); + + if (has_python_method(pyobj, "__cmp__")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(b))); + + pyret = run_python_method(pyobj, "__cmp__", args); + + if (pyret != NULL) + { + if (PyLong_Check(pyret)) + result = PyLong_AsLong(pyret); + } + + Py_DECREF(args); + + Py_XDECREF(pyret); + + } + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = registre visé par la procédure. * +* * +* Description : Traduit un opérande en version humainement lisible. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLine *line) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define ARCH_OPERAND_PRINT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _print, "$self, line, /", \ + METH_VARARGS, \ + "Abstract method used to print the operand into a rendering" \ + " line, which is a provided pychrysalide.glibext.BufferLine" \ + " instance." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(operand)); + + if (has_python_method(pyobj, "_print")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line))); + + pyret = run_python_method(pyobj, "_print", args); + + Py_DECREF(args); + + Py_XDECREF(pyret); + + } + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* binary = informations relatives au binaire chargé. * +* * +* Description : Construit un petit résumé concis de l'opérande. * +* * +* Retour : Chaîne de caractères à libérer après usage ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand, const GLoadedBinary *binary) +{ + char *result; /* Description à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + +#define ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _build_tooltip, "$self, line, /", \ + METH_VARARGS, \ + "Abstract method used to build a tooltip text shown when the" \ + " mouse is over the operand.\n" \ + "\n" \ + "A pychrysalide.analysis.LoadedBinary instance is provided in" \ + " case of need." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(operand)); + + if (has_python_method(pyobj, "_build_tooltip")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary))); + + pyret = run_python_method(pyobj, "_build_tooltip", args); + + if (pyret != NULL) + { + ret = PyUnicode_Check(pyret); + + if (ret) + result = strdup(PyUnicode_AsUTF8(pyret)); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + PyGILState_Release(gstate); + + return result; } @@ -146,6 +363,51 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse /****************************************************************************** * * +* 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 'ArchOperand'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_arch_operand_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + int ret; /* Bilan de lecture des args. */ + const GArchOperand *reg_a; /* Premier élément à traiter */ + const GArchOperand *reg_b; /* Second élément à traiter */ + int status; /* Résultat d'une comparaison */ + + ret = PyObject_IsInstance(b, (PyObject *)get_python_arch_operand_type()); + if (!ret) + { + result = Py_NotImplemented; + goto cmp_done; + } + + reg_a = G_ARCH_OPERAND(pygobject_get(a)); + reg_b = G_ARCH_OPERAND(pygobject_get(b)); + + status = py_arch_operand___cmp___wrapper(reg_a, reg_b); + + result = status_to_rich_cmp_state(status, op); + + cmp_done: + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -159,6 +421,9 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse PyTypeObject *get_python_arch_operand_type(void) { static PyMethodDef py_arch_operand_methods[] = { + ARCH_OPERAND_CMP_WRAPPER, + ARCH_OPERAND_PRINT_WRAPPER, + ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER, { NULL } }; @@ -175,7 +440,9 @@ PyTypeObject *get_python_arch_operand_type(void) .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, - .tp_doc = "PyChrysalide instruction operand.", + .tp_doc = ARCH_OPERAND_DOC, + + .tp_richcompare = py_arch_operand_richcompare, .tp_methods = py_arch_operand_methods, .tp_getset = py_arch_operand_getseters, |