/* Chrysalide - Outil d'analyse de fichiers binaires * constval.c - conversion de constantes C en équivalent Python * * 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 "constval.h" #include #include #include #include #include "access.h" #include "helpers.h" /* Objet à vocation interne */ typedef struct _PyConstvalObject { PyLongObject base; /* A laisser en premier */ /** * Le champ suivant est rajouté à la fin de l'allocation * de l'objet PyLongObject, dont la taille est dynamique. */ /*char *name;*/ /* Désignation de la valeur */ } PyConstvalObject; /* Interdit la création d'une instance depuis Python. */ static PyObject *py_constval_new(PyTypeObject *, PyObject *, PyObject *); /* Libère la mémoire occupée par la description en sortie. */ static void py_constval_finalize(PyObject *); /* Calcule l'emplacement reservé pour une désignation de valeur. */ static char **py_constval_compute_name_ptr(PyConstvalObject *); /* Construit une représentation textuelle de l'objet. */ static PyObject *py_constval_str(PyObject *); /* Fournit une réduction de l'objet en vue d'une sérialisation. */ static PyObject *py_constval_reduce(PyObject *, PyObject *); /****************************************************************************** * * * Paramètres : type = type du nouvel objet à mettre en place. * * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * * * * Description : Interdit la création d'une instance depuis Python. * * * * Retour : NULL. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_constval_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Instance à retourner */ unsigned long value; /* Valeur entière */ const char *name; /* Désignation humaine */ int ret; /* Bilan de lecture des args. */ ret = PyArg_ParseTuple(args, "ks", &value, &name); if (!ret) return NULL; result = build_constval_from_c_code(name, value); return result; } /****************************************************************************** * * * Paramètres : self = valeur constante C convertie en Python. * * * * Description : Libère la mémoire occupée par la description en sortie. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void py_constval_finalize(PyObject *self) { PyConstvalObject *constval; /* Autre version de l'objet */ char **ptr; /* Désignation à convertir */ constval = (PyConstvalObject *)self; ptr = py_constval_compute_name_ptr(constval); free(*ptr); } /****************************************************************************** * * * Paramètres : self = valeur constante C convertie en Python. * * * * Description : Calcule l'emplacement reservé pour une désignation de valeur.* * * * Retour : Pointeur vers l'adresse de désignation. * * * * Remarques : - * * * ******************************************************************************/ static char **py_constval_compute_name_ptr(PyConstvalObject *self) { digit *result; /* Adresse mémoire à retourner */ Py_ssize_t size; /* Taille supplémentaire */ size = Py_SIZE(&self->base); if (size < 0) size = -size; result = &self->base.ob_digit[size]; return (char **)result; } /****************************************************************************** * * * Paramètres : self = valeur constante C convertie en Python. * * * * Description : Construit une représentation textuelle de l'objet. * * * * Retour : Chaîne de caractère Unicode. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_constval_str(PyObject *self) { PyObject *result; /* Elément à retourner */ PyConstvalObject *constval; /* Autre version de l'objet */ char **ptr; /* Désignation à convertir */ constval = (PyConstvalObject *)self; ptr = py_constval_compute_name_ptr(constval); result = PyUnicode_FromString(*ptr); return result; } /****************************************************************************** * * * Paramètres : self = architecture concernée par la procédure. * * args = instruction représentant le point de départ. * * * * Description : Fournit une réduction de l'objet en vue d'une sérialisation. * * * * Retour : Données utiles à une reconstruction. * * * * Remarques : - * * * ******************************************************************************/ static PyObject *py_constval_reduce(PyObject *self, PyObject *args) { PyObject *result; /* Données à retourner */ unsigned long value; /* Valeur entière */ PyConstvalObject *constval; /* Autre version de l'objet */ char **ptr; /* Désignation à convertir */ PyObject *params; /* Paramètres de construction */ value = PyLong_AsUnsignedLong(self); constval = (PyConstvalObject *)self; ptr = py_constval_compute_name_ptr(constval); params = Py_BuildValue("(ks)", value, *ptr); result = Py_BuildValue("(OO)", Py_TYPE(self), params); Py_DECREF(params); 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_py_constval_type(void) { static PyMethodDef py_constval_methods[] = { { "__reduce__", py_constval_reduce, METH_NOARGS, "__reduce__($self, /)\n--\n\nProvide information to rebuild the object." }, { NULL } }; static PyGetSetDef py_constval_getseters[] = { { NULL } }; static PyTypeObject py_constval_type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.PyConstvalObject", .tp_basicsize = offsetof(PyLongObject, ob_digit), .tp_itemsize = sizeof(digit), .tp_str = py_constval_str, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, .tp_doc = "PyChrysalide object for C constant values", .tp_methods = py_constval_methods, .tp_getset = py_constval_getseters, .tp_base = &PyLong_Type, .tp_new = py_constval_new, .tp_finalize = py_constval_finalize, }; return &py_constval_type; } /****************************************************************************** * * * Paramètres : - * * * * Description : Prend en charge l'objet 'pychrysalide.PyConstvalObject'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_python_py_constval_is_registered(void) { PyTypeObject *type; /* Type Python 'PyConstval...' */ PyObject *module; /* Module à recompléter */ type = get_python_py_constval_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide"); if (PyType_Ready(type) != 0) return false; if (!register_python_module_object(module, type)) return false; } return true; } /****************************************************************************** * * * Paramètres : name = désignation de la constante à représenter. * * value = valeur de la constante à représenter. * * * * Description : Construit un objet pour valeur constante en C. * * * * Retour : Object Python résultant de la construction opérée. * * * * Remarques : - * * * ******************************************************************************/ PyObject *build_constval_from_c_code(const char *name, unsigned long value) { PyObject *result; /* Instance à retourner */ PyLongObject *tmp; /* Construction temporaire */ Py_ssize_t size; /* Taille supplémentaire */ PyTypeObject *type; /* Type Python 'PyConstval...' */ PyConstvalObject *constval; /* Autre version de l'objet */ char **ptr; /* Désignation à convertir */ /* Création d'une base de travail */ tmp = (PyLongObject *)PyLong_FromUnsignedLong(value); size = Py_SIZE(tmp); if (size < 0) size = -size; /** * En allouant 2 éléments "digit" supplémentaires, on est assuré * de disposer de l'espace nécessaire pour la conservation * d'un pointeur. */ result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) + (size + 2) * sizeof(digit)); if (!result) { PyErr_NoMemory(); return NULL; } type = get_python_py_constval_type(); result = PyObject_INIT_VAR(result, type, size); /* Copie de la valeur */ Py_SIZE(result) = Py_SIZE(tmp); constval = (PyConstvalObject *)result; while (--size >= 0) constval->base.ob_digit[size] = tmp->ob_digit[size]; Py_DECREF(tmp); /* Copie de la désignation */ ptr = py_constval_compute_name_ptr(constval); *ptr = strdup(name); return result; }