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, | 
