From 8e76324b01e5b4979f346f0bc8c84372477a3d38 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 10 May 2017 22:21:56 +0200 Subject: Rewritten the whole bitfield management. --- ChangeLog | 36 ++ plugins/pychrysa/arch/vmpa.c | 46 +-- plugins/pychrysa/common/Makefile.am | 1 + plugins/pychrysa/common/bits.c | 653 ++++++++++++++++++++++++++++++++++++ plugins/pychrysa/common/bits.h | 48 +++ plugins/pychrysa/common/module.c | 2 + plugins/pychrysa/format/symbol.c | 39 +-- plugins/pychrysa/helpers.c | 54 +++ plugins/pychrysa/helpers.h | 3 + src/analysis/disass/area.c | 57 +++- src/analysis/disass/dragon.c | 2 +- src/common/bits.c | 293 +++++----------- src/common/bits.h | 22 +- tests/common/bitfield.py | 106 ++++++ tests/common/pathname.py | 4 +- 15 files changed, 1058 insertions(+), 308 deletions(-) create mode 100644 plugins/pychrysa/common/bits.c create mode 100644 plugins/pychrysa/common/bits.h create mode 100644 tests/common/bitfield.py diff --git a/ChangeLog b/ChangeLog index 123b47e..48e8334 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +17-05-10 Cyrille Bagard + + * plugins/pychrysa/arch/vmpa.c: + Typo. Update code. + + * plugins/pychrysa/common/Makefile.am: + Add the 'bits.[ch]' files to libpychrysacommon_la_SOURCES. + + * plugins/pychrysa/common/bits.c: + * plugins/pychrysa/common/bits.h: + New entries: provide Python bindings for bitfields. + + * plugins/pychrysa/common/module.c: + Register the new bindings. + + * plugins/pychrysa/format/symbol.c: + Typo. Update code. + + * plugins/pychrysa/helpers.c: + * plugins/pychrysa/helpers.h: + Translate C comparison status to Python rich comparison status. + + * src/analysis/disass/area.c: + * src/analysis/disass/dragon.c: + Update code. + + * src/common/bits.c: + * src/common/bits.h: + Rewrite the whole bitfield management. + + * tests/common/bitfield.py: + New entry: test the new bitfield bindings. + + * tests/common/pathname.py: + Typo. + 17-05-08 Cyrille Bagard * src/arch/raw.c: diff --git a/plugins/pychrysa/arch/vmpa.c b/plugins/pychrysa/arch/vmpa.c index 10acf35..03434d7 100644 --- a/plugins/pychrysa/arch/vmpa.c +++ b/plugins/pychrysa/arch/vmpa.c @@ -186,8 +186,9 @@ static PyObject *py_vmpa_to_str(PyObject *obj) /****************************************************************************** * * -* Paramètres : obj = objet Python à tenter de convertir. * -* addr = structure équivalente pour Chrysalide. * +* 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 'vmpa_t'. * * * @@ -199,7 +200,7 @@ static PyObject *py_vmpa_to_str(PyObject *obj) static PyObject *py_vmpa_richcompare(PyObject *a, PyObject *b, int op) { - PyObject *result; /* Chaîne à retourner */ + PyObject *result; /* Bilan à retourner */ vmpa2t *addr_a; /* Première adresse à traiter */ vmpa2t addr_b; /* Seconde adresse à traiter */ @@ -829,8 +830,9 @@ static PyObject *py_mrange_to_str(PyObject *obj) /****************************************************************************** * * -* Paramètres : obj = objet Python à tenter de convertir. * -* addr = structure équivalente pour Chrysalide. * +* 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 'mrange_t'. * * * @@ -842,7 +844,7 @@ static PyObject *py_mrange_to_str(PyObject *obj) static PyObject *py_mrange_richcompare(PyObject *a, PyObject *b, int op) { - PyObject *result; /* Chaîne à retourner */ + PyObject *result; /* Bilan à retourner */ mrange_t *range_a; /* Premier espace à traiter */ mrange_t *range_b; /* Second espace à traiter */ int status; /* Résultat d'une comparaison */ @@ -854,37 +856,7 @@ static PyObject *py_mrange_richcompare(PyObject *a, PyObject *b, int op) status = cmp_mrange(range_a, range_b); - switch (op) - { - case Py_LT: - result = status < 0 ? Py_True : Py_False; - break; - - case Py_LE: - result = status <= 0 ? Py_True : Py_False; - break; - - case Py_EQ: - result = status == 0 ? Py_True : Py_False; - break; - - case Py_NE: - result = status != 0 ? Py_True : Py_False; - break; - - case Py_GT: - result = status > 0 ? Py_True : Py_False; - break; - - case Py_GE: - result = status >= 0 ? Py_True : Py_False; - break; - - default: - result = Py_NotImplemented; - break; - - } + result = status_to_rich_cmp_state(status, op); Py_INCREF(result); diff --git a/plugins/pychrysa/common/Makefile.am b/plugins/pychrysa/common/Makefile.am index 93d92ac..0637229 100644 --- a/plugins/pychrysa/common/Makefile.am +++ b/plugins/pychrysa/common/Makefile.am @@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libpychrysacommon.la libpychrysacommon_la_SOURCES = \ + bits.h bits.c \ fnv1a.h fnv1a.c \ module.h module.c \ pathname.h pathname.c diff --git a/plugins/pychrysa/common/bits.c b/plugins/pychrysa/common/bits.c new file mode 100644 index 0000000..33f81c3 --- /dev/null +++ b/plugins/pychrysa/common/bits.c @@ -0,0 +1,653 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.c - équivalent Python du fichier "common/bits.c" + * + * Copyright (C) 2017 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 "bits.h" + + +#include "../helpers.h" + + + +/* Encapsulation d'un champ de bits */ +typedef struct _py_bitfield_t +{ + PyObject_HEAD /* A laisser en premier */ + + bitfield_t *native; /* Champ de bits représenté */ + +} py_bitfield_t; + + + +/* Crée un nouvel objet Python de type 'bitfield_t'. */ +static PyObject *py_bitfield_new(PyTypeObject *, PyObject *, PyObject *); + +/* Crée une copie d'un champ de bits classique. */ +static PyObject *py_bitfield_dup(PyObject *, PyObject *); + +/* Effectue une opération de type 'and' avec le type 'bitfield'. */ +static PyObject *py_bitfield_nb_and(PyObject *, PyObject *); + +/* Effectue une opération de type 'or' avec le type 'bitfield'. */ +static PyObject *py_bitfield_nb_or(PyObject *, PyObject *); + +/* Effectue une comparaison avec un objet Python 'bitfield'. */ +static PyObject *py_bitfield_richcompare(PyObject *, PyObject *, int); + +/* Bascule à 0 un champ de bits dans son intégralité. */ +static PyObject *py_bitfield_reset_all(PyObject *, PyObject *); + +/* Bascule à 1 un champ de bits dans son intégralité. */ +static PyObject *py_bitfield_set_all(PyObject *, PyObject *); + +/* Bascule à 0 une partie d'un champ de bits. */ +static PyObject *py_bitfield_reset(PyObject *, PyObject *); + +/* Bascule à 1 une partie d'un champ de bits. */ +static PyObject *py_bitfield_set(PyObject *, PyObject *); + +/* Détermine si un bit est à 1 dans un champ de bits. */ +static PyObject *py_bitfield_test(PyObject *, PyObject *); + +/* Détermine si un ensemble de bits est à 0 dans un champ. */ +static PyObject *py_bitfield_test_none(PyObject *, PyObject *); + +/* Détermine si un ensemble de bits est à 1 dans un champ. */ +static PyObject *py_bitfield_test_all(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'bitfield_t'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + py_bitfield_t *result; /* Instance à retourner */ + unsigned long length; /* Taille du champ à créer */ + int state; /* Initialisation par défaut */ + int ret; /* Bilan de lecture des args. */ + + ret = PyArg_ParseTuple(args, "kp", &length, &state); + if (!ret) return NULL; + + result = (py_bitfield_t *)type->tp_alloc(type, 0); + + result->native = create_bit_field(length, state); + + return (PyObject *)result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à dupliquer. * +* args = non utilisé ici. * +* * +* Description : Crée une copie d'un champ de bits classique. * +* * +* Retour : Champ de bits mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_dup(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + py_bitfield_t *bf; /* Instance à manipuler */ + + bf = (py_bitfield_t *)self; + + result = build_from_internal_bitfield(bf->native);; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : o1 = premier élément concerné par l'opération. * +* o2 = second élément concerné par l'opération. * +* * +* Description : Effectue une opération de type 'and' avec le type 'bitfield'.* +* * +* Retour : Résultat de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_nb_and(PyObject *o1, PyObject *o2) +{ + PyObject *result; /* Résultat à retourner */ + int ret; /* Bilan de compatibilité */ + py_bitfield_t *bf_1; /* Instance à manipuler #1 */ + py_bitfield_t *bf_2; /* Instance à manipuler #2 */ + py_bitfield_t *new; /* Nouvelle version en place */ + + ret = PyObject_IsInstance(o2, (PyObject *)get_python_bitfield_type()); + if (!ret) + { + result = NULL; + goto pbna_done; + } + + bf_1 = (py_bitfield_t *)o1; + bf_2 = (py_bitfield_t *)o2; + + result = build_from_internal_bitfield(bf_1->native); + + new = (py_bitfield_t *)result; + + and_bit_field(new->native, bf_2->native); + + pbna_done: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : o1 = premier élément concerné par l'opération. * +* o2 = second élément concerné par l'opération. * +* * +* Description : Effectue une opération de type 'or' avec le type 'bitfield'. * +* * +* Retour : Résultat de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_nb_or(PyObject *o1, PyObject *o2) +{ + PyObject *result; /* Résultat à retourner */ + int ret; /* Bilan de compatibilité */ + py_bitfield_t *bf_1; /* Instance à manipuler #1 */ + py_bitfield_t *bf_2; /* Instance à manipuler #2 */ + py_bitfield_t *new; /* Nouvelle version en place */ + + ret = PyObject_IsInstance(o2, (PyObject *)get_python_bitfield_type()); + if (!ret) + { + result = NULL; + goto pbna_done; + } + + bf_1 = (py_bitfield_t *)o1; + bf_2 = (py_bitfield_t *)o2; + + result = build_from_internal_bitfield(bf_1->native); + + new = (py_bitfield_t *)result; + + or_bit_field(new->native, bf_2->native); + + pbna_done: + + return result; + +} + + +/****************************************************************************** +* * +* 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 'bitfield'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf_a; /* Instance à manipuler #1 */ + py_bitfield_t *bf_b; /* Instance à manipuler #2 */ + int status; /* Résultat d'une comparaison */ + + ret = PyObject_IsInstance(b, (PyObject *)get_python_bitfield_type()); + if (!ret) + { + result = Py_NotImplemented; + goto cmp_done; + } + + bf_a = (py_bitfield_t *)a; + bf_b = (py_bitfield_t *)b; + + status = compare_bit_fields(bf_a->native, bf_b->native); + + result = status_to_rich_cmp_state(status, op); + + cmp_done: + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à modifier. * +* args = non utilisé ici. * +* * +* Description : Bascule à 0 un champ de bits dans son intégralité. * +* * +* Retour : Rien (None). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_reset_all(PyObject *self, PyObject *args) +{ + py_bitfield_t *bf; /* Instance à manipuler */ + + bf = (py_bitfield_t *)self; + + reset_all_in_bit_field(bf->native); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à modifier. * +* args = non utilisé ici. * +* * +* Description : Bascule à 1 un champ de bits dans son intégralité. * +* * +* Retour : Rien (None). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_set_all(PyObject *self, PyObject *args) +{ + py_bitfield_t *bf; /* Instance à manipuler */ + + bf = (py_bitfield_t *)self; + + set_all_in_bit_field(bf->native); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Bascule à 0 une partie d'un champ de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_reset(PyObject *self, PyObject *args) +{ + unsigned long first; /* Indice du premier bit testé */ + unsigned long count; /* Nombre de bits à analyser */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + + ret = PyArg_ParseTuple(args, "kk", &first, &count); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + reset_in_bit_field(bf->native, first, count); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Bascule à 1 une partie d'un champ de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_set(PyObject *self, PyObject *args) +{ + unsigned long first; /* Indice du premier bit testé */ + unsigned long count; /* Nombre de bits à analyser */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + + ret = PyArg_ParseTuple(args, "kk", &first, &count); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + set_in_bit_field(bf->native, first, count); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Détermine si un bit est à 1 dans un champ de bits. * +* * +* Retour : true si le bit correspondant est à l'état haut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long n; /* Indice du bit à traiter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + + ret = PyArg_ParseTuple(args, "k", &n); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_in_bit_field(bf->native, n); + + result = status ? Py_True : Py_False; + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Détermine si un ensemble de bits est à 0 dans un champ. * +* * +* Retour : True si les bits correspondants sont à l'état bas. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_none(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + unsigned long count; /* Nombre de bits à analyser */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + + ret = PyArg_ParseTuple(args, "kk", &first, &count); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_none_in_bit_field(bf->native, first, count); + + result = status ? Py_True : Py_False; + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Détermine si un ensemble de bits est à 1 dans un champ. * +* * +* Retour : True si les bits correspondants sont à l'état haut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + unsigned long count; /* Nombre de bits à analyser */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + + ret = PyArg_ParseTuple(args, "kk", &first, &count); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_all_in_bit_field(bf->native, first, count); + + result = status ? Py_True : Py_False; + + Py_INCREF(result); + + 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_bitfield_type(void) +{ + static PyNumberMethods py_bitfield_nb_proto = { + + .nb_and = py_bitfield_nb_and, + .nb_or = py_bitfield_nb_or + + }; + + static PyMethodDef py_bitfield_methods[] = { + { + "dup", py_bitfield_dup, + METH_NOARGS, + "dup(self, /)\n--\n\nDuplicate a bitfield." + }, + { + "reset_all", py_bitfield_reset_all, + METH_NOARGS, + "reset_all(self, /)\n--\n\nSwitch to 0 all bits in a bitfield." + }, + { + "set_all", py_bitfield_set_all, + METH_NOARGS, + "set_all(self, /)\n--\n\nSwitch to 1 all bits in a bitfield." + }, + { + "reset", py_bitfield_reset, + METH_VARARGS, + "reset(self, first, count, /)\n--\n\nSwitch to 0 a part of bits in a bitfield." + }, + { + "set", py_bitfield_set, + METH_VARARGS, + "set(self, first, count, /)\n--\n\nSwitch to 1 a part of bits in a bitfield." + }, + { + "test", py_bitfield_test, + METH_VARARGS, + "test(self, n, /)\n--\n\nTest if a given bit is set in a bitfield." + }, + { + "test_none", py_bitfield_test_none, + METH_VARARGS, + "test_none(self, first, count, /)\n--\n\nTest a range of bits to 0." + }, + { + "test_all", py_bitfield_test_all, + METH_VARARGS, + "test_all(self, first, count, /)\n--\n\nTest a range of bits to 1." + }, + { NULL } + }; + + static PyGetSetDef py_bitfield_getseters[] = { + { NULL } + }; + + static PyTypeObject py_bitfield_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.common.bitfield", + .tp_basicsize = sizeof(py_bitfield_t), + + .tp_as_number = &py_bitfield_nb_proto, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "Python object for bitfield_t.", + + .tp_richcompare = py_bitfield_richcompare, + + .tp_methods = py_bitfield_methods, + .tp_getset = py_bitfield_getseters, + .tp_new = (newfunc)py_bitfield_new + + }; + + return &py_bitfield_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.common.bitfield'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_bitfield(PyObject *module) +{ + PyTypeObject *py_bitfield_type; /* Type Python pour 'bitfield' */ + int ret; /* Bilan d'un appel */ + + py_bitfield_type = get_python_bitfield_type(); + + if (PyType_Ready(py_bitfield_type) != 0) + return false; + + Py_INCREF(py_bitfield_type); + ret = PyModule_AddObject(module, "bitfield", (PyObject *)py_bitfield_type); + + return (ret == 0); + +} + + +/****************************************************************************** +* * +* Paramètres : field = structure interne à copier en objet Python. * +* * +* Description : Convertit une structure de type 'bitfield' en objet Python. * +* * +* Retour : Object Python résultant de la conversion opérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *build_from_internal_bitfield(const bitfield_t *field) +{ + py_bitfield_t *result; /* Instance à retourner */ + PyTypeObject *type; /* Type à instancier */ + + type = get_python_bitfield_type(); + + result = (py_bitfield_t *)type->tp_alloc(type, 0); + + result->native = dup_bit_field(field); + + return (PyObject *)result; + +} diff --git a/plugins/pychrysa/common/bits.h b/plugins/pychrysa/common/bits.h new file mode 100644 index 0000000..41465ce --- /dev/null +++ b/plugins/pychrysa/common/bits.h @@ -0,0 +1,48 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.h - prototypes pour l'équivalent Python du fichier "common/bits.h" + * + * Copyright (C) 2017 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_PYCHRYSA_COMMON_BITS_H +#define _PLUGINS_PYCHRYSA_COMMON_BITS_H + + +#include +#include + + +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_bitfield_type(void); + +/* Prend en charge l'objet 'pychrysalide.common.bitfield'. */ +bool register_python_bitfield(PyObject *); + +/* Convertit une structure de type 'bitfield' en objet Python. */ +PyObject *build_from_internal_bitfield(const bitfield_t *); + + + +#endif /* _PLUGINS_PYCHRYSA_COMMON_BITS_H */ diff --git a/plugins/pychrysa/common/module.c b/plugins/pychrysa/common/module.c index cc23631..cc2623a 100644 --- a/plugins/pychrysa/common/module.c +++ b/plugins/pychrysa/common/module.c @@ -25,6 +25,7 @@ #include "module.h" +#include "bits.h" #include "fnv1a.h" #include "pathname.h" @@ -76,6 +77,7 @@ bool add_common_module_to_python_module(PyObject *super) result = true; + result &= register_python_bitfield(module); result &= register_python_fnv1a(module); result &= register_python_pathname(module); diff --git a/plugins/pychrysa/format/symbol.c b/plugins/pychrysa/format/symbol.c index 53fb9c9..75f226a 100644 --- a/plugins/pychrysa/format/symbol.c +++ b/plugins/pychrysa/format/symbol.c @@ -85,8 +85,9 @@ static bool py_binary_symbol_define_constants(PyTypeObject *); /****************************************************************************** * * -* Paramètres : obj = objet Python à tenter de convertir. * -* addr = structure équivalente pour Chrysalide. * +* 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 'BinSymbol'. * * * @@ -98,7 +99,7 @@ static bool py_binary_symbol_define_constants(PyTypeObject *); static PyObject *py_binary_symbol_richcompare(PyObject *a, PyObject *b, int op) { - PyObject *result; /* Chaîne à retourner */ + PyObject *result; /* Bilan à retourner */ int ret; /* Bilan de lecture des args. */ const GBinSymbol *sym_a; /* Premier élément à traiter */ const GBinSymbol *sym_b; /* Second élément à traiter */ @@ -116,37 +117,7 @@ static PyObject *py_binary_symbol_richcompare(PyObject *a, PyObject *b, int op) status = g_binary_symbol_cmp(&sym_a, &sym_b); - switch (op) - { - case Py_LT: - result = status < 0 ? Py_True : Py_False; - break; - - case Py_LE: - result = status <= 0 ? Py_True : Py_False; - break; - - case Py_EQ: - result = status == 0 ? Py_True : Py_False; - break; - - case Py_NE: - result = status != 0 ? Py_True : Py_False; - break; - - case Py_GT: - result = status > 0 ? Py_True : Py_False; - break; - - case Py_GE: - result = status >= 0 ? Py_True : Py_False; - break; - - default: - result = Py_NotImplemented; - break; - - } + result = status_to_rich_cmp_state(status, op); cmp_done: diff --git a/plugins/pychrysa/helpers.c b/plugins/pychrysa/helpers.c index 36d0d76..df1df05 100644 --- a/plugins/pychrysa/helpers.c +++ b/plugins/pychrysa/helpers.c @@ -31,6 +31,60 @@ /****************************************************************************** * * +* Paramètres : status = bilan de comparaison à traduire. * +* op = type de comparaison menée. * +* * +* Description : Traduit pour Python le bilan d'une comparaison riche. * +* * +* Retour : Objet Python à référencer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *status_to_rich_cmp_state(int status, int op) +{ + PyObject *result; /* Bilan àretourner */ + + switch (op) + { + case Py_LT: + result = status < 0 ? Py_True : Py_False; + break; + + case Py_LE: + result = status <= 0 ? Py_True : Py_False; + break; + + case Py_EQ: + result = status == 0 ? Py_True : Py_False; + break; + + case Py_NE: + result = status != 0 ? Py_True : Py_False; + break; + + case Py_GT: + result = status > 0 ? Py_True : Py_False; + break; + + case Py_GE: + result = status >= 0 ? Py_True : Py_False; + break; + + default: + result = Py_NotImplemented; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : target = propriétaire de la routine visée. * * method = désignation de la fonction à appeler. * * * diff --git a/plugins/pychrysa/helpers.h b/plugins/pychrysa/helpers.h index 3e079b7..950c85b 100644 --- a/plugins/pychrysa/helpers.h +++ b/plugins/pychrysa/helpers.h @@ -31,6 +31,9 @@ +/* Traduit pour Python le bilan d'une comparaison riche. */ +PyObject *status_to_rich_cmp_state(int, int); + /* Indique si une routine Python existe ou non. */ bool has_python_method(PyObject *, const char *); diff --git a/src/analysis/disass/area.c b/src/analysis/disass/area.c index f01b89c..ed53b28 100644 --- a/src/analysis/disass/area.c +++ b/src/analysis/disass/area.c @@ -60,6 +60,7 @@ typedef struct _mem_area bitfield_t *processed; /* Octets traités dans la zone */ GArchInstruction **instructions; /* Instructions en place */ size_t count; /* Quantité d'instructions */ + GMutex mutex; /* Garantie d'atomicité */ bool is_exec; /* Zone exécutable ? */ @@ -249,6 +250,7 @@ static void init_mem_area_from_addr(mem_area *area, const vmpa2t *addr, phys_t l area->processed = create_bit_field(len, false); area->instructions = (GArchInstruction **)calloc(len, sizeof(GArchInstruction *)); area->count = 0; + g_mutex_init(&area->mutex); } @@ -284,6 +286,8 @@ static void fini_mem_area(mem_area *area) free(area->instructions); + g_mutex_clear(&area->mutex); + } @@ -365,6 +369,10 @@ static bool mark_range_in_mem_area_as_processed(mem_area *area, GArchInstruction phys_t offset; /* Décallage de départ */ phys_t i; /* Boucle de parcours */ GArchInstruction *old; /* Instruction remplacée */ + const mrange_t *old_range; /* Emplacement de l'instruction*/ + phys_t old_len; /* Taille de cette instruction */ + + /* Détermination de la couverture */ start = get_mrange_addr(&area->range); @@ -374,21 +382,23 @@ static bool mark_range_in_mem_area_as_processed(mem_area *area, GArchInstruction offset = compute_vmpa_diff(start, addr); - result = set_atomic_in_bit_field(area->processed, offset, len); + /* Début des choses sérieuses */ + + g_mutex_lock(&area->mutex); - /* Si l'instruction était bien la première à s'inscrire... */ + /* Vérification de couverture */ - result |= force; + result = test_none_in_bit_field(area->processed, offset, len); - if (result) + if (!result) { - assert(area->instructions[offset] == NULL || force); + if (!force) goto mrimaap_exit; /** * Un cas de remplacement forcé intervient en ARM, lorsque qu'une * instruction utilise une valeur immédiate placée dans le code. * - * Cette valeur est référencée en tant que symbole. + * Cette valeur doit être référencée en tant que donnée. * * Mais cette même valeur a pu être désassemblée en tant que code * exécutable si le flot d'exécution s'est poursuivi jusqu'à elle. @@ -400,33 +410,52 @@ static bool mark_range_in_mem_area_as_processed(mem_area *area, GArchInstruction * On réinitialise donc la zone couverte par la nouvelle instruction. */ - for (i = 0; force && i < len; i++) + for (i = 0; i < len; i++) { old = area->instructions[offset + i]; if (old != NULL) { + old_range = g_arch_instruction_get_range(old); + old_len = get_mrange_length(old_range); + + reset_in_bit_field(area->processed, offset + i, old_len); + g_object_unref(G_OBJECT(old)); area->instructions[offset + i] = NULL; + g_atomic_pointer_add(&area->count, -1); + } } + result = true; + + } + + /* Inscription de l'instruction dans les comptes */ + #ifndef NDEBUG - for (i = 0; i < len; i++) - assert(area->instructions[offset + i] == NULL); + for (i = 0; i < len; i++) + assert(area->instructions[offset + i] == NULL); #endif - area->instructions[offset] = instr; - g_atomic_pointer_add(&area->count, 1); + set_in_bit_field(area->processed, offset, len); - /* Au passage, association du contenu */ - g_arch_instruction_set_global_content(instr, area->content); + area->instructions[offset] = instr; + g_atomic_pointer_add(&area->count, 1); - } + /* Au passage, association du contenu */ + g_arch_instruction_set_global_content(instr, area->content); + + mrimaap_exit: + + /* Fin des choses sérieuses */ + + g_mutex_unlock(&area->mutex); return result; diff --git a/src/analysis/disass/dragon.c b/src/analysis/disass/dragon.c index 75ccc40..9064af8 100644 --- a/src/analysis/disass/dragon.c +++ b/src/analysis/disass/dragon.c @@ -591,7 +591,7 @@ void compute_all_dominators(dragon_node *nodes, size_t count) set_in_bit_field(inter, k, 1); - if (!is_bit_field_equal_to(node->bits, inter)) + if (compare_bit_fields(node->bits, inter) != 0) { copy_bit_field(node->bits, inter); changed = true; diff --git a/src/common/bits.c b/src/common/bits.c index d4d5074..4d4731a 100644 --- a/src/common/bits.c +++ b/src/common/bits.c @@ -37,22 +37,13 @@ struct _bitfield_t size_t length; /* Nombre de bits représentés */ size_t requested; /* Nombre de mots alloués */ - void *tail; /* Limite du tableau de bits */ - - GMutex mutex; /* Garantie d'atomicité */ unsigned long bits[0]; /* Mémoire d'accès associée */ }; /* Crée un champ de bits initialisé à zéro. */ -static bitfield_t *_create_bit_field(size_t, bool, size_t); - -/* Crée une copie de champ de bits initialisé à zéro. */ -static bitfield_t *_create_bit_field_from(const bitfield_t *, bool, size_t); - -/* Crée une copie d'un champ de bits classique. */ -static bitfield_t *_dup_bit_field(const bitfield_t *, size_t); +static bitfield_t *_create_bit_field(size_t); /* Détermine si un ensemble de bits est homogène dans un champ. */ static bool test_state_in_bit_field(const bitfield_t *, size_t, size_t, bool); @@ -62,8 +53,6 @@ static bool test_state_in_bit_field(const bitfield_t *, size_t, size_t, bool); /****************************************************************************** * * * Paramètres : length = nom de bits du champ à représenter. * -* state = état initial de chaque des bits. * -* extra = espace mémoire supplémentaire à ajouter au final. * * * * Description : Crée un champ de bits initialisé à zéro. * * * @@ -73,31 +62,22 @@ static bool test_state_in_bit_field(const bitfield_t *, size_t, size_t, bool); * * ******************************************************************************/ -static bitfield_t *_create_bit_field(size_t length, bool state, size_t extra) +static bitfield_t *_create_bit_field(size_t length) { bitfield_t *result; /* Création à retourner */ size_t requested; /* Nombre de mots à allouer */ size_t base; /* Allocation de base en octets*/ - requested = length / sizeof(unsigned long); - if (length % sizeof(unsigned long) != 0) requested++; + requested = length / (sizeof(unsigned long) * 8); + if (length % (sizeof(unsigned long) * 8) != 0) requested++; base = sizeof(bitfield_t) + requested * sizeof(unsigned long); - result = (bitfield_t *)malloc(base + extra); + result = (bitfield_t *)malloc(base); result->length = length; result->requested = requested; - result->tail = ((char *)result) + base; - - g_mutex_init(&result->mutex); - - if (state) - set_all_in_bit_field(result); - else - reset_all_in_bit_field(result); - return result; } @@ -105,7 +85,7 @@ static bitfield_t *_create_bit_field(size_t length, bool state, size_t extra) /****************************************************************************** * * -* Paramètres : length = nom de bits du champ à représenter. * +* Paramètres : length = nombre de bits du champ à représenter. * * state = état initial de chaque des bits. * * * * Description : Crée un champ de bits initialisé. * @@ -118,38 +98,25 @@ static bitfield_t *_create_bit_field(size_t length, bool state, size_t extra) bitfield_t *create_bit_field(size_t length, bool state) { - return _create_bit_field(length, state, 0); - -} + bitfield_t *result; /* Création à retourner */ + result = _create_bit_field(length); -/****************************************************************************** -* * -* Paramètres : field = champde bits à prendre pour modèle. * -* state = état initial de chaque des bits. * -* extra = espace mémoire supplémentaire à ajouter au final. * -* * -* Description : Crée une copie de champ de bits initialisé à zéro. * -* * -* Retour : Champ de bits mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ + if (state) + set_all_in_bit_field(result); + else + reset_all_in_bit_field(result); -static bitfield_t *_create_bit_field_from(const bitfield_t *field, bool state, size_t extra) -{ - return _create_bit_field(field->length, state, extra); + return result; } /****************************************************************************** * * -* Paramètres : field = champde bits à prendre pour modèle. * -* state = état initial de chaque des bits. * +* Paramètres : field = champ de bits à dupliquer. * * * -* Description : Crée une copie de champ de bits initialisé à zéro. * +* Description : Crée une copie d'un champ de bits classique. * * * * Retour : Champ de bits mis en place. * * * @@ -157,9 +124,15 @@ static bitfield_t *_create_bit_field_from(const bitfield_t *field, bool state, s * * ******************************************************************************/ -bitfield_t *create_bit_field_from(const bitfield_t *field, bool state) +bitfield_t *dup_bit_field(const bitfield_t *field) { - return _create_bit_field_from(field, state, 0); + bitfield_t *result; /* Copie à retourner */ + + result = _create_bit_field(field->length); + + memcpy(result->bits, field->bits, result->requested * sizeof(unsigned long)); + + return result; } @@ -178,8 +151,6 @@ bitfield_t *create_bit_field_from(const bitfield_t *field, bool state) void delete_bit_field(bitfield_t *field) { - g_mutex_clear(&field->mutex); - free(field); } @@ -209,49 +180,64 @@ void copy_bit_field(bitfield_t *dest, const bitfield_t *src) /****************************************************************************** * * -* Paramètres : field = champ de bits à dupliquer. * -* extra = espace mémoire supplémentaire à ajouter au final. * +* Paramètres : a = premier champ à analyser. * +* b = second champ à analyser. * * * -* Description : Crée une copie d'un champ de bits classique. * +* Description : Compare deux champs de bits entre eux. * * * -* Retour : Champ de bits mis en place. * +* Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ -static bitfield_t *_dup_bit_field(const bitfield_t *field, size_t extra) +int compare_bit_fields(const bitfield_t *a, const bitfield_t *b) { - bitfield_t *result; /* Copie à retourner */ - size_t requested; /* Nombre de mots à allouer */ + int result; /* Bilan à retourner */ + unsigned long final; /* Masque de la partie finale */ + size_t i; /* Boucle de parcours */ + unsigned long val_a; /* Valeur d'un mot de A */ + unsigned long val_b; /* Valeur d'un mot de B */ - result = _create_bit_field(field->length, false, extra); + result = 0; - requested = field->length / sizeof(unsigned long); - if (field->length % sizeof(unsigned long) != 0) requested++; + if (a->length > b->length) + result = 1; - memcpy(result->bits, field->bits, requested * sizeof(unsigned long)); + else if (a->length < b->length) + result = -1; - return result; + if (result == 0) + { + final = a->length % sizeof(unsigned long); -} + if (final == 0) + final = ~0lu; + else + final = (1 << final) - 1; + for (i = 0; i < a->requested && result == 0; i++) + { + val_a = a->bits[i]; + val_b = b->bits[i]; -/****************************************************************************** -* * -* Paramètres : field = champ de bits à dupliquer. * -* * -* Description : Crée une copie d'un champ de bits classique. * -* * -* Retour : Champ de bits mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ + if ((i + 1) == a->requested) + { + val_a &= final; + val_b &= final; + } -bitfield_t *dup_bit_field(const bitfield_t *field) -{ - return _dup_bit_field(field, 0); + if (val_a > val_b) + result = 1; + + else if (val_a < val_b) + result = -1; + + } + + } + + return result; } @@ -300,7 +286,7 @@ void set_all_in_bit_field(bitfield_t *field) * first = indice du premier bit à traiter. * * count = nombre de bits à marquer. * * * -* Description : Bascule à 1 une partie d'un champ de bits. * +* Description : Bascule à 0 une partie d'un champ de bits. * * * * Retour : - * * * @@ -308,7 +294,7 @@ void set_all_in_bit_field(bitfield_t *field) * * ******************************************************************************/ -void set_in_bit_field(bitfield_t *field, size_t first, size_t count) +void reset_in_bit_field(bitfield_t *field, size_t first, size_t count) { size_t last; /* Point d'arrêt de la boucle */ size_t i; /* Boucle de parcours */ @@ -324,7 +310,7 @@ void set_in_bit_field(bitfield_t *field, size_t first, size_t count) index = i / (sizeof(unsigned long) * 8); remaining = i % (sizeof(unsigned long) * 8); - field->bits[index] |= (1ul << remaining); + field->bits[index] &= ~(1ul << remaining); } @@ -337,79 +323,34 @@ void set_in_bit_field(bitfield_t *field, size_t first, size_t count) * first = indice du premier bit à traiter. * * count = nombre de bits à marquer. * * * -* Description : Bascule à 1 de façon atomique une partie d'un champ de bits. * +* Description : Bascule à 1 une partie d'un champ de bits. * * * -* Retour : true si la zone traitée était entièrement vierge. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -bool set_atomic_in_bit_field(bitfield_t *field, size_t first, size_t count) +void set_in_bit_field(bitfield_t *field, size_t first, size_t count) { - bool result; /* Bilan à retourner */ - size_t start; /* Mot de départ */ - size_t end; /* Mot d'arrivée */ + size_t last; /* Point d'arrêt de la boucle */ + size_t i; /* Boucle de parcours */ + size_t index; /* Cellule de tableau visée */ size_t remaining; /* Nombre de bits restants */ - unsigned long mask; /* Nouvelle valeur à insérer */ - unsigned long oldval; /* Ancienne valeur présente */ - - start = first / (sizeof(unsigned long) * 8); - end = (first + count - 1) / (sizeof(unsigned long) * 8); - - if (start == end) - { - remaining = first % (sizeof(unsigned long) * 8); - assert(count > 0 && count <= (sizeof(unsigned long) * 8)); - - if (count == 64) - { - assert(remaining == 0); - mask = ~0lu; - } - else - { - mask = (1lu << count) - 1; - mask <<= remaining; - } - - /** - * Pour une raison inconnue, l'appel suivant est parfois sans effet : - * - * oldval = g_atomic_pointer_or(&field->bits[start], mask); - * - * On bascule donc dans l'équivalent plus long à exécuter... - */ - - g_mutex_lock(&field->mutex); - - oldval = field->bits[start]; - - field->bits[start] |= mask; - - g_mutex_unlock(&field->mutex); - - result = ((oldval & mask) == 0); + last = first + count; - assert(test_all_in_bit_field(field, first, count)); + assert(last <= field->length); - } - else + for (i = first; i < last; i++) { - g_mutex_lock(&field->mutex); - - result = test_none_in_bit_field(field, first, count); - - if (result) - set_in_bit_field(field, first, count); + index = i / (sizeof(unsigned long) * 8); + remaining = i % (sizeof(unsigned long) * 8); - g_mutex_unlock(&field->mutex); + field->bits[index] |= (1ul << remaining); } - return result; - } @@ -465,7 +406,7 @@ void or_bit_field(bitfield_t *dest, const bitfield_t *src) /****************************************************************************** * * -* Paramètres : field = champ de bits à modifier. * +* Paramètres : field = champ de bits à consulter. * * n = indice du bit à traiter. * * * * Description : Détermine si un bit est à 1 dans un champ de bits. * @@ -503,7 +444,7 @@ bool test_in_bit_field(const bitfield_t *field, size_t n) * * * Description : Détermine si un ensemble de bits est homogène dans un champ. * * * -* Retour : true si le bit correspondant est à l'état haut. * +* Retour : true si les bits correspondants sont à l'état indiqué. * * * * Remarques : - * * * @@ -539,13 +480,13 @@ static bool test_state_in_bit_field(const bitfield_t *field, size_t first, size_ /****************************************************************************** * * -* Paramètres : field = champ de bits à modifier. * +* Paramètres : field = champ de bits à consulter. * * first = indice du premier bit à traiter. * -* count = nombre de bits à marquer. * +* count = nombre de bits à analyser. * * * * Description : Détermine si un ensemble de bits est à 0 dans un champ. * * * -* Retour : true si le bit correspondant est à l'état haut. * +* Retour : true si les bits correspondants sont à l'état bas. * * * * Remarques : - * * * @@ -564,13 +505,13 @@ bool test_none_in_bit_field(const bitfield_t *field, size_t first, size_t count) /****************************************************************************** * * -* Paramètres : field = champ de bits à modifier. * +* Paramètres : field = champ de bits à consulter. * * first = indice du premier bit à traiter. * -* count = nombre de bits à marquer. * +* count = nombre de bits à analyser. * * * * Description : Détermine si un ensemble de bits est à 1 dans un champ. * * * -* Retour : true si le bit correspondant est à l'état haut. * +* Retour : true si les bits correspondants sont à l'état haut. * * * * Remarques : - * * * @@ -585,61 +526,3 @@ bool test_all_in_bit_field(const bitfield_t *field, size_t first, size_t count) return result; } - - -/****************************************************************************** -* * -* Paramètres : a = premier champ de bits à comparer. * -* b = second champ de bits à comparer. * -* * -* Description : Indique si deux champs de bits sont identiques ou non. * -* * -* Retour : true si les champs de bits sont égaux ou false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool is_bit_field_equal_to(const bitfield_t *a, const bitfield_t *b) -{ - bool result; /* Résultat à retourner */ - size_t i; /* Boucle de parcours */ - size_t remaining; /* Nombre de bits restants */ - - if (a->length != b->length) - return false; - - result = true; - - for (i = 0; i < (a->requested - 1) && result; i++) - result = (a->bits[i] == b->bits[i]); - - if (result) - { - remaining = a->length % sizeof(unsigned long); - - if (remaining == 0) - result = (a->bits[i] == b->bits[i]); - - else - { - remaining = (1 << (remaining + 1)) - 1; - - result = ((a->bits[i] & remaining) == (b->bits[i] & remaining)); - - } - - } - - return result; - -} - - - - -unsigned long gfw(const bitfield_t *field) -{ - return field->bits[0]; - -} diff --git a/src/common/bits.h b/src/common/bits.h index 4a2937f..b9fc0e6 100644 --- a/src/common/bits.h +++ b/src/common/bits.h @@ -36,8 +36,8 @@ typedef struct _bitfield_t bitfield_t; /* Crée un champ de bits initialisé. */ bitfield_t *create_bit_field(size_t, bool); -/* Crée une copie de champ de bits initialisé à zéro. */ -bitfield_t *create_bit_field_from(const bitfield_t *, bool); +/* Crée une copie d'un champ de bits classique. */ +bitfield_t *dup_bit_field(const bitfield_t *); /* Supprime de la mémoire un champ de bits donné. */ void delete_bit_field(bitfield_t *); @@ -45,8 +45,8 @@ void delete_bit_field(bitfield_t *); /* Copie un champ de bits dans un autre. */ void copy_bit_field(bitfield_t *, const bitfield_t *); -/* Crée une copie d'un champ de bits classique. */ -bitfield_t *dup_bit_field(const bitfield_t *); +/* Compare deux champs de bits entre eux. */ +int compare_bit_fields(const bitfield_t *, const bitfield_t *); /* Bascule à 0 un champ de bits dans son intégralité. */ void reset_all_in_bit_field(bitfield_t *); @@ -54,12 +54,12 @@ void reset_all_in_bit_field(bitfield_t *); /* Bascule à 1 un champ de bits dans son intégralité. */ void set_all_in_bit_field(bitfield_t *); +/* Bascule à 0 une partie d'un champ de bits. */ +void reset_in_bit_field(bitfield_t *, size_t, size_t); + /* Bascule à 1 une partie d'un champ de bits. */ void set_in_bit_field(bitfield_t *, size_t, size_t); -/* Bascule à 1 de façon atomique une partie d'un champ de bits. */ -bool set_atomic_in_bit_field(bitfield_t *, size_t, size_t); - /* Réalise une opération ET logique entre deux champs de bits. */ void and_bit_field(bitfield_t *, const bitfield_t *); @@ -75,14 +75,6 @@ bool test_none_in_bit_field(const bitfield_t *, size_t, size_t); /* Détermine si un ensemble de bits est à 1 dans un champ. */ bool test_all_in_bit_field(const bitfield_t *, size_t, size_t); -/* Indique si deux champs de bits sont identiques ou non. */ -bool is_bit_field_equal_to(const bitfield_t *, const bitfield_t *); - - - - -unsigned long gfw(const bitfield_t *); - #endif /* _COMMON_BITS_H */ diff --git a/tests/common/bitfield.py b/tests/common/bitfield.py new file mode 100644 index 0000000..ec61291 --- /dev/null +++ b/tests/common/bitfield.py @@ -0,0 +1,106 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +# Tests minimalistes pour valider la construction de chemins relatifs et absolus. + + +from chrysacase import ChrysalideTestCase +from pychrysalide.common import bitfield + + +class TestBitfields(ChrysalideTestCase): + """TestCase for common.bitfield*""" + + def testDuplicateBitfield(self): + """Check duplicated bitfield value.""" + + bf = bitfield(10, 0) + + bf2 = bf.dup() + + self.assertEqual(bf, bf2) + + + def testBitfieldValues(self): + """Evaluate bitfields basic values.""" + + bf_a = bitfield(75, 1) + + bf_b = bitfield(75, 0) + + self.assertNotEqual(bf_a, bf_b) + + bf_a = bitfield(75, 1) + + bf_b = bitfield(75, 0) + bf_b.set_all() + + self.assertEqual(bf_a, bf_b) + + bf_a = bitfield(75, 1) + bf_a.reset_all() + + bf_b = bitfield(75, 0) + + self.assertEqual(bf_a, bf_b) + + + def testBitfieldLogicalOperations(self): + """Perform logical operations on bitfields.""" + + bf_a = bitfield(75, 1) + + bf_b = bitfield(75, 0) + + bf_f = bf_a & bf_b + + self.assertEqual(bf_f, bf_b) + + bf_f = bf_a | bf_b + + self.assertEqual(bf_f, bf_a) + + + def testBitfieldSwitch(self): + """Switch various bits in bitfields.""" + + bf_1 = bitfield(75, 1) + + bf_0 = bitfield(75, 0) + + bf_t = bitfield(75, 0) + + for i in range(75): + bf_t.set(i, 1) + + self.assertEqual(bf_t, bf_1) + + for i in range(75): + bf_t.reset(i, 1) + + self.assertEqual(bf_t, bf_0) + + + def testBitfieldBits(self): + """Test bits in bitfields.""" + + bf = bitfield(54, 1) + + self.assertTrue(bf.test(0)) + + self.assertTrue(bf.test(53)) + + self.assertTrue(bf.test_all(0, 54)) + + self.assertFalse(bf.test_none(0, 54)) + + bf = bitfield(54, 0) + + self.assertFalse(bf.test(0)) + + self.assertFalse(bf.test(53)) + + self.assertFalse(bf.test_all(0, 54)) + + self.assertTrue(bf.test_none(0, 54)) diff --git a/tests/common/pathname.py b/tests/common/pathname.py index 5cd238c..3692434 100644 --- a/tests/common/pathname.py +++ b/tests/common/pathname.py @@ -9,13 +9,13 @@ from chrysacase import ChrysalideTestCase from pychrysalide.common import pathname -class TestRestrictedContent(ChrysalideTestCase): +class TestPathNames(ChrysalideTestCase): """TestCase for common.pathname.build*""" @classmethod def setUpClass(cls): - super(TestRestrictedContent, cls).setUpClass() + super(TestPathNames, cls).setUpClass() cls._tests = [ { -- cgit v0.11.2-87-g4458