From 362ff8ddd7fac8a10c7cccae303d2ce5ea6dd7f2 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 13 Oct 2020 23:24:12 +0200 Subject: Defined proper Python bindings for basic types. --- plugins/pychrysalide/analysis/types/Makefile.am | 1 + plugins/pychrysalide/analysis/types/basic.c | 97 +++++---------- plugins/pychrysalide/analysis/types/constants.c | 155 ++++++++++++++++++++++++ plugins/pychrysalide/analysis/types/constants.h | 42 +++++++ src/analysis/types/basic.c | 8 +- src/analysis/types/basic.h | 2 +- src/analysis/types/literal.c | 2 +- tests/analysis/types/basic.py | 28 +++++ 8 files changed, 263 insertions(+), 72 deletions(-) create mode 100644 plugins/pychrysalide/analysis/types/constants.c create mode 100644 plugins/pychrysalide/analysis/types/constants.h create mode 100644 tests/analysis/types/basic.py diff --git a/plugins/pychrysalide/analysis/types/Makefile.am b/plugins/pychrysalide/analysis/types/Makefile.am index 53ae320..3a69345 100644 --- a/plugins/pychrysalide/analysis/types/Makefile.am +++ b/plugins/pychrysalide/analysis/types/Makefile.am @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libpychrysaanalysistypes.la libpychrysaanalysistypes_la_SOURCES = \ array.h array.c \ basic.h basic.c \ + constants.h constants.c \ cse.h cse.c \ encaps.h encaps.c \ expr.h expr.c \ diff --git a/plugins/pychrysalide/analysis/types/basic.c b/plugins/pychrysalide/analysis/types/basic.c index e421389..539bcad 100644 --- a/plugins/pychrysalide/analysis/types/basic.c +++ b/plugins/pychrysalide/analysis/types/basic.c @@ -32,6 +32,7 @@ #include +#include "constants.h" #include "../type.h" #include "../../access.h" #include "../../helpers.h" @@ -42,10 +43,7 @@ static PyObject *py_basic_type_new(PyTypeObject *, PyObject *, PyObject *); /* Fournit le type de base géré par le type. */ -static PyObject *py_basic_type_get_base_type(PyObject *, void *); - -/* Définit les constantes pour les types de base. */ -static bool py_basic_type_define_constants(PyTypeObject *); +static PyObject *py_basic_type_get_base(PyObject *, void *); @@ -66,11 +64,22 @@ static bool py_basic_type_define_constants(PyTypeObject *); static PyObject *py_basic_type_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Instance à retourner */ - unsigned long base; /* Type de base à créer */ + BaseType base; /* Type de base à créer */ int ret; /* Bilan de lecture des args. */ GDataType *dtype; /* Version GLib du type */ - ret = PyArg_ParseTuple(args, "k", &base); +#define BASIC_TYPE_DOC \ + "The BasicType class handles all the primary types of data, such as" \ + " integers, characters or floating numbers.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " BasicType(base)" \ + "\n" \ + "Where *base* is one of the pychrysalide.analysis.types.BasicType.BaseType" \ + " values, except *BaseType.INVALID*." + + ret = PyArg_ParseTuple(args, "O&", convert_to_basic_type_base_type, &base); if (!ret) return NULL; if (base >= BTP_INVALID) @@ -101,17 +110,25 @@ static PyObject *py_basic_type_new(PyTypeObject *type, PyObject *args, PyObject * * ******************************************************************************/ -static PyObject *py_basic_type_get_base_type(PyObject *self, void *closure) +static PyObject *py_basic_type_get_base(PyObject *self, void *closure) { PyObject *result; /* Résultat à retourner */ GBasicType *type; /* Version GLib du type */ BaseType base; /* Type de base à renvoyer */ +#define BASIC_TYPE_BASE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + base, py_basic_type, \ + "Provide the internal identifier of the basic type.\n" \ + "\n" \ + "This property provides a pychrysalide.analysis.BaseType value." \ +) + type = G_BASIC_TYPE(pygobject_get(self)); - base = g_basic_type_get_base_type(type); + base = g_basic_type_get_base(type); - result = PyLong_FromUnsignedLong(base); + result = cast_with_constants_group_from_type(get_python_basic_type_type(), "BaseType", base); return result; @@ -137,10 +154,7 @@ PyTypeObject *get_python_basic_type_type(void) }; static PyGetSetDef py_basic_type_getseters[] = { - { - "base", py_basic_type_get_base_type, NULL, - "Provide the internal identifier of the basic type.", NULL - }, + BASIC_TYPE_BASE_ATTRIB, { NULL } }; @@ -153,7 +167,7 @@ PyTypeObject *get_python_basic_type_type(void) .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "PyChrysalide basic type", + .tp_doc = BASIC_TYPE_DOC, .tp_methods = py_basic_type_methods, .tp_getset = py_basic_type_getseters, @@ -168,59 +182,6 @@ PyTypeObject *get_python_basic_type_type(void) /****************************************************************************** * * -* Paramètres : obj_type = type dont le dictionnaire est à compléter. * -* * -* Description : Définit les constantes pour les types de base. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool py_basic_type_define_constants(PyTypeObject *obj_type) -{ - bool result; /* Bilan à retourner */ - - result = true; - - result &= PyDict_AddULongMacro(obj_type, BTP_VOID); - result &= PyDict_AddULongMacro(obj_type, BTP_WCHAR_T); - result &= PyDict_AddULongMacro(obj_type, BTP_BOOL); - result &= PyDict_AddULongMacro(obj_type, BTP_CHAR); - result &= PyDict_AddULongMacro(obj_type, BTP_SCHAR); - result &= PyDict_AddULongMacro(obj_type, BTP_UCHAR); - result &= PyDict_AddULongMacro(obj_type, BTP_SHORT); - result &= PyDict_AddULongMacro(obj_type, BTP_USHORT); - result &= PyDict_AddULongMacro(obj_type, BTP_INT); - result &= PyDict_AddULongMacro(obj_type, BTP_UINT); - result &= PyDict_AddULongMacro(obj_type, BTP_LONG); - result &= PyDict_AddULongMacro(obj_type, BTP_ULONG); - result &= PyDict_AddULongMacro(obj_type, BTP_LONG_LONG); - result &= PyDict_AddULongMacro(obj_type, BTP_ULONG_LONG); - result &= PyDict_AddULongMacro(obj_type, BTP_INT128); - result &= PyDict_AddULongMacro(obj_type, BTP_UINT128); - result &= PyDict_AddULongMacro(obj_type, BTP_FLOAT); - result &= PyDict_AddULongMacro(obj_type, BTP_DOUBLE); - result &= PyDict_AddULongMacro(obj_type, BTP_LONG_DOUBLE); - result &= PyDict_AddULongMacro(obj_type, BTP_FLOAT128); - result &= PyDict_AddULongMacro(obj_type, BTP_ELLIPSIS); - result &= PyDict_AddULongMacro(obj_type, BTP_754R_64); - result &= PyDict_AddULongMacro(obj_type, BTP_754R_128); - result &= PyDict_AddULongMacro(obj_type, BTP_754R_32); - result &= PyDict_AddULongMacro(obj_type, BTP_754R_16); - result &= PyDict_AddULongMacro(obj_type, BTP_CHAR32_T); - result &= PyDict_AddULongMacro(obj_type, BTP_CHAR16_T); - - result &= PyDict_AddULongMacro(obj_type, BTP_INVALID); - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : module = module dont la définition est à compléter. * * * * Description : Prend en charge l'objet 'pychrysalide.....types.BasicType'. * @@ -251,7 +212,7 @@ bool ensure_python_basic_type_is_registered(void) if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type, get_python_data_type_type())) return false; - if (!py_basic_type_define_constants(type)) + if (!define_basic_type_constants(type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/constants.c b/plugins/pychrysalide/analysis/types/constants.c new file mode 100644 index 0000000..6562fa0 --- /dev/null +++ b/plugins/pychrysalide/analysis/types/constants.c @@ -0,0 +1,155 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes de base pour les types + * + * Copyright (C) 2020 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 "constants.h" + + +#include + + +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux types de base. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_basic_type_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "VOID", BTP_VOID); + if (result) result = add_const_to_group(values, "WCHAR_T", BTP_WCHAR_T); + if (result) result = add_const_to_group(values, "BOOL", BTP_BOOL); + if (result) result = add_const_to_group(values, "CHAR", BTP_CHAR); + if (result) result = add_const_to_group(values, "SCHAR", BTP_SCHAR); + if (result) result = add_const_to_group(values, "UCHAR", BTP_UCHAR); + if (result) result = add_const_to_group(values, "SHORT", BTP_SHORT); + if (result) result = add_const_to_group(values, "USHORT", BTP_USHORT); + if (result) result = add_const_to_group(values, "INT", BTP_INT); + if (result) result = add_const_to_group(values, "UINT", BTP_UINT); + if (result) result = add_const_to_group(values, "LONG", BTP_LONG); + if (result) result = add_const_to_group(values, "ULONG", BTP_ULONG); + if (result) result = add_const_to_group(values, "LONG_LONG", BTP_LONG_LONG); + if (result) result = add_const_to_group(values, "ULONG_LONG", BTP_ULONG_LONG); + if (result) result = add_const_to_group(values, "INT128", BTP_INT128); + if (result) result = add_const_to_group(values, "UINT128", BTP_UINT128); + if (result) result = add_const_to_group(values, "FLOAT", BTP_FLOAT); + if (result) result = add_const_to_group(values, "DOUBLE", BTP_DOUBLE); + if (result) result = add_const_to_group(values, "LONG_DOUBLE", BTP_LONG_DOUBLE); + if (result) result = add_const_to_group(values, "FLOAT128", BTP_FLOAT128); + if (result) result = add_const_to_group(values, "ELLIPSIS", BTP_ELLIPSIS); + if (result) result = add_const_to_group(values, "754R_64", BTP_754R_64); + if (result) result = add_const_to_group(values, "754R_128", BTP_754R_128); + if (result) result = add_const_to_group(values, "754R_32", BTP_754R_32); + if (result) result = add_const_to_group(values, "754R_16", BTP_754R_16); + if (result) result = add_const_to_group(values, "754R_N", BTP_754R_N); + if (result) result = add_const_to_group(values, "CHAR32_T", BTP_CHAR32_T); + if (result) result = add_const_to_group(values, "CHAR16_T", BTP_CHAR16_T); + if (result) result = add_const_to_group(values, "AUTO", BTP_AUTO); + if (result) result = add_const_to_group(values, "DECL_AUTO", BTP_DECL_AUTO); + if (result) result = add_const_to_group(values, "INVALID", BTP_INVALID); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "BaseType", values, + "Identifiers for basic data types."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en constante BaseType. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_basic_type_base_type(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to BaseType"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > BTP_INVALID) + { + PyErr_SetString(PyExc_TypeError, "invalid value for BaseType"); + result = 0; + } + + else + *((BaseType *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/types/constants.h b/plugins/pychrysalide/analysis/types/constants.h new file mode 100644 index 0000000..9598f75 --- /dev/null +++ b/plugins/pychrysalide/analysis/types/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes de base pour les types + * + * Copyright (C) 2020 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_ANALYSIS_TYPES_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H + + +#include +#include + + + +/* Définit les constantes relatives aux types de base. */ +bool define_basic_type_constants(PyTypeObject *); + +/* Tente de convertir en constante BaseType. */ +int convert_to_basic_type_base_type(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H */ diff --git a/src/analysis/types/basic.c b/src/analysis/types/basic.c index 755a6f6..a907f2d 100644 --- a/src/analysis/types/basic.c +++ b/src/analysis/types/basic.c @@ -371,8 +371,12 @@ static char *g_basic_type_to_string(const GBasicType *type, bool include) * * ******************************************************************************/ -BaseType g_basic_type_get_base_type(const GBasicType *type) +BaseType g_basic_type_get_base(const GBasicType *type) { - return type->type; + BaseType result; /* Type de base à retourner */ + + result = type->type; + + return result; } diff --git a/src/analysis/types/basic.h b/src/analysis/types/basic.h index d2b3055..ad7308f 100644 --- a/src/analysis/types/basic.h +++ b/src/analysis/types/basic.h @@ -93,7 +93,7 @@ GType g_basic_type_get_type(void); GDataType *g_basic_type_new(BaseType); /* Fournit le type de base géré par le type. */ -BaseType g_basic_type_get_base_type(const GBasicType *); +BaseType g_basic_type_get_base(const GBasicType *); diff --git a/src/analysis/types/literal.c b/src/analysis/types/literal.c index 831fcb7..3a9e5cf 100644 --- a/src/analysis/types/literal.c +++ b/src/analysis/types/literal.c @@ -243,7 +243,7 @@ static char *g_literal_type_to_string(const GLiteralType *type, bool include) { char *result; /* Valeur à renvoyer */ - switch (g_basic_type_get_base_type(G_BASIC_TYPE(type->orig))) + switch (g_basic_type_get_base(G_BASIC_TYPE(type->orig))) { case BTP_BOOL: result = strdup(type->value.int_val ? "true" : "false"); diff --git a/tests/analysis/types/basic.py b/tests/analysis/types/basic.py new file mode 100644 index 0000000..7b7403b --- /dev/null +++ b/tests/analysis/types/basic.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.types import BasicType + + +class TestDataType(ChrysalideTestCase): + """TestCase for analysis.DataType.""" + + + def testBasicTypeConstructor(self): + """Build some basic types.""" + + tp = BasicType(BasicType.BaseType.VOID) + + self.assertEqual(str(tp), 'void') + + self.assertEqual(tp.base, BasicType.BaseType.VOID) + + with self.assertRaisesRegex(TypeError, 'Bad basic type.'): + + tp = BasicType(BasicType.BaseType.INVALID) + + with self.assertRaisesRegex(TypeError, 'invalid value for BaseType'): + + tp = BasicType(0x1234) -- cgit v0.11.2-87-g4458