From 0c6e15aa59918b7d3a1e63258e3f6792266d62e0 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 13 Dec 2018 22:38:11 +0100 Subject: Provided a representation for constant values imported from C code. --- plugins/pychrysalide/Makefile.am | 1 + plugins/pychrysalide/constval.c | 300 +++++++++++++++++++++++++++++++++++++++ plugins/pychrysalide/constval.h | 45 ++++++ plugins/pychrysalide/helpers.c | 3 +- plugins/pychrysalide/pychrysa.c | 2 + tests/constval.py | 22 +++ 6 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 plugins/pychrysalide/constval.c create mode 100644 plugins/pychrysalide/constval.h create mode 100644 tests/constval.py diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am index 8051bb9..3fe13af 100644 --- a/plugins/pychrysalide/Makefile.am +++ b/plugins/pychrysalide/Makefile.am @@ -6,6 +6,7 @@ libdir = $(pluginslibdir) pychrysalide_la_SOURCES = \ access.h access.c \ + constval.h constval.c \ dt.h dt.c \ helpers.h helpers.c \ plugin.h plugin.c \ diff --git a/plugins/pychrysalide/constval.c b/plugins/pychrysalide/constval.c new file mode 100644 index 0000000..b6d20aa --- /dev/null +++ b/plugins/pychrysalide/constval.c @@ -0,0 +1,300 @@ + +/* 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 "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. + */ + + /*const 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 *); + +/* Calcule l'emplacement reservé pour une désignation de valeur. */ +static const char **py_constval_compute_name_ptr(PyConstvalObject *); + +/* Construit une représentation textuelle de l'objet. */ +static PyObject *py_constval_str(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) +{ + PyErr_Format(PyExc_RuntimeError, _("%s is meant to be only used from C code"), type->tp_name); + + return NULL; + +} + + +/****************************************************************************** +* * +* 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 const 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 (const 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 */ + const char **ptr; /* Désignation à convertir */ + + constval = (PyConstvalObject *)self; + + ptr = py_constval_compute_name_ptr(constval); + + result = PyUnicode_FromString(*ptr); + + 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[] = { + { 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, + + .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, + + }; + + 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 */ + const 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 = name; + + return result; + +} diff --git a/plugins/pychrysalide/constval.h b/plugins/pychrysalide/constval.h new file mode 100644 index 0000000..1099ee5 --- /dev/null +++ b/plugins/pychrysalide/constval.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constval.h - prototypes pour la 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 + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_CONSTVAL_H +#define _PLUGINS_PYCHRYSALIDE_CONSTVAL_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_py_constval_type(void); + +/* Prend en charge l'objet 'pychrysalide.PyConstvalObject'. */ +bool ensure_python_py_constval_is_registered(void); + +/* Construit un objet pour valeur constante en C. */ +PyObject *build_constval_from_c_code(const char *, unsigned long); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_CONSTVAL_H */ diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index be580a4..dae2aea 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -32,6 +32,7 @@ #include "access.h" +#include "constval.h" @@ -222,7 +223,7 @@ bool PyDict_AddIntConstant(PyTypeObject *obj_type, const char *key, long value) PyObject *item; /* Nouvel élément à insérer */ int ret; /* Bilan d'un ajout */ - item = PyLong_FromLong(value); + item = build_constval_from_c_code(key, value); ret = PyDict_SetItemString(obj_type->tp_dict, key, item); result = (ret != -1); diff --git a/plugins/pychrysalide/pychrysa.c b/plugins/pychrysalide/pychrysa.c index 514442a..7772592 100644 --- a/plugins/pychrysalide/pychrysa.c +++ b/plugins/pychrysalide/pychrysa.c @@ -44,6 +44,7 @@ #include "access.h" +#include "constval.h" #include "dt.h" #include "helpers.h" #include "plugin.h" @@ -386,6 +387,7 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) if (status) status = add_mangling_module(result); if (status) status = ensure_python_plugin_module_is_registered(); + if (status) status = ensure_python_py_constval_is_registered(); if (status) status = ensure_python_py_struct_is_registered(); if (status) status = populate_analysis_module(); diff --git a/tests/constval.py b/tests/constval.py new file mode 100644 index 0000000..4863d39 --- /dev/null +++ b/tests/constval.py @@ -0,0 +1,22 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +from chrysacase import ChrysalideTestCase +from pychrysalide import PyConstvalObject +from pychrysalide.arch import ArchInstruction + + +class TestConstVal(ChrysalideTestCase): + """TestCase for PyConstvalObject.""" + + + def testGI(self): + """Validate the PyConstvalObject implementation.""" + + with self.assertRaises(RuntimeError): + cv = PyConstvalObject() + + self.assertEqual(ArchInstruction.ILT_JUMP, 1) + + self.assertEqual(str(ArchInstruction.ILT_JUMP), 'ILT_JUMP') -- cgit v0.11.2-87-g4458