From 7cb4e815b691d05d8c0aea9decf56b9dbc41dfa6 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 14 Aug 2019 00:04:53 +0200
Subject: Used a Python enumeration for the binary symbol status.

---
 plugins/pychrysalide/format/Makefile.am |   1 +
 plugins/pychrysalide/format/constants.c |  71 ++++++++++++
 plugins/pychrysalide/format/constants.h |  39 +++++++
 plugins/pychrysalide/format/symbol.c    |  17 ++-
 plugins/pychrysalide/helpers.c          | 199 ++++++++++++++++++++++++++++++++
 plugins/pychrysalide/helpers.h          |  29 +++++
 tests/format/symbol.py                  |  26 +++++
 7 files changed, 377 insertions(+), 5 deletions(-)
 create mode 100644 plugins/pychrysalide/format/constants.c
 create mode 100644 plugins/pychrysalide/format/constants.h
 create mode 100644 tests/format/symbol.py

diff --git a/plugins/pychrysalide/format/Makefile.am b/plugins/pychrysalide/format/Makefile.am
index 6d50da7..24890ec 100644
--- a/plugins/pychrysalide/format/Makefile.am
+++ b/plugins/pychrysalide/format/Makefile.am
@@ -2,6 +2,7 @@
 noinst_LTLIBRARIES = libpychrysaformat.la
 
 libpychrysaformat_la_SOURCES =			\
+	constants.h constants.c				\
 	executable.h executable.c			\
 	flat.h flat.c						\
 	format.h format.c					\
diff --git a/plugins/pychrysalide/format/constants.c b/plugins/pychrysalide/format/constants.c
new file mode 100644
index 0000000..9e63fdd
--- /dev/null
+++ b/plugins/pychrysalide/format/constants.c
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.c - équivalent Python partiel du fichier "plugins/dex/dex_def.h"
+ *
+ * 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 "constants.h"
+
+
+#include <format/symbol.h>
+
+
+#include "../helpers.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
+*  Description : Définit les constantes pour le format Dex.                   *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_binary_symbol_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "INTERNAL", SSS_INTERNAL);
+    if (result) result = add_const_to_group(values, "EXPORTED", SSS_EXPORTED);
+    if (result) result = add_const_to_group(values, "IMPORTED", SSS_IMPORTED);
+    if (result) result = add_const_to_group(values, "DYNAMIC", SSS_DYNAMIC);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group(type, false, "SymbolStatus", values, "Status of a symbol visibility.");
+
+ exit:
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/format/constants.h b/plugins/pychrysalide/format/constants.h
new file mode 100644
index 0000000..6515f35
--- /dev/null
+++ b/plugins/pychrysalide/format/constants.h
@@ -0,0 +1,39 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * constants.h - prototypes pour l'ajout des constantes liées aux formats
+ *
+ * Copyright (C) 2019 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_FORMAT_CONSTANTS_H
+#define _PLUGINS_PYCHRYSALIDE_FORMAT_CONSTANTS_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Définit les constantes pour les symboles binaires. */
+bool define_binary_symbol_constants(PyTypeObject *);
+
+
+
+#endif  /* _PLUGINS_PYCHRYSALIDE_FORMAT_CONSTANTS_H */
diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c
index 3295e8c..af03473 100644
--- a/plugins/pychrysalide/format/symbol.c
+++ b/plugins/pychrysalide/format/symbol.c
@@ -36,6 +36,7 @@
 #include <format/symbol.h>
 
 
+#include "constants.h"
 #include "../access.h"
 #include "../helpers.h"
 #include "../analysis/routine.h"
@@ -349,10 +350,16 @@ static PyObject *py_binary_symbol_get_status(PyObject *self, void *closure)
     GBinSymbol *symbol;                     /* Elément à consulter         */
     SymbolStatus status;                    /* Visibilité du symbole fourni*/
 
+#define BINARY_SYMBOL_STATUS_ATTRIB PYTHON_GET_DEF_FULL     \
+(                                                           \
+    status, py_binary_symbol,                               \
+    "Status of the symbol's visibility."                    \
+)
+
     symbol = G_BIN_SYMBOL(pygobject_get(self));
     status = g_binary_symbol_get_status(symbol);
 
-    result = PyLong_FromLong(status);
+    result = cast_with_constants_group(get_python_binary_symbol_type(), "SymbolStatus", status);
 
     return result;
 
@@ -432,10 +439,7 @@ PyTypeObject *get_python_binary_symbol_type(void)
             "range", py_binary_symbol_get_range, py_binary_symbol_set_range,
             "Range covered by the symbol.", NULL
         },
-        {
-            "status", py_binary_symbol_get_status, NULL,
-            "Status of the symbol's visibility.", NULL
-        },
+        BINARY_SYMBOL_STATUS_ATTRIB,
         { NULL }
     };
 
@@ -498,6 +502,9 @@ bool ensure_python_binary_symbol_is_registered(void)
         if (!py_binary_symbol_define_constants(type))
             return false;
 
+        if (!define_binary_symbol_constants(type))
+            return false;
+
     }
 
     return true;
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index 6ffb4fe..6e13d3c 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -939,3 +939,202 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp
     return result;
 
 }
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                         TRANSFERT DES VALEURS CONSTANTES                           */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : owner  = type dont le dictionnaire est à compléter.          *
+*                flags  = indique le type d'énumération ciblée.               *
+*                name   = désignation humaine du groupe à constituer.         *
+*                values = noms et valeurs associées.                          *
+*                doc    = documentation à associer au groupe.                 *
+*                                                                             *
+*  Description : Officialise un groupe de constantes avec sémentique.         *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool attach_constants_group(PyTypeObject *owner, bool flags, const char *name, PyObject *values, const char *doc)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *enum_mod;                     /* Module Python enum          */
+    PyObject *class;                        /* Classe "Enum*"              */
+    PyObject *str_obj;                      /* Conversion en Python        */
+    int ret;                                /* Bilan d'une insertion       */
+    PyObject *args;                         /* Arguments de la construction*/
+    PyObject *kwargs;                       /* Mots clefs en complément    */
+    PyObject *new;                          /* Nouvelle instance en place  */
+    PyObject *features;                     /* Module à recompléter        */
+    PyObject *features_dict;                /* Dictionnaire à compléter    */
+
+    result = false;
+
+    /* Recherche de la classe Python */
+
+    enum_mod = PyImport_ImportModule("enum");
+
+    if (enum_mod == NULL)
+        goto no_mod;
+
+    if (flags)
+        class = PyObject_GetAttrString(enum_mod, "IntFlag");
+    else
+        class = PyObject_GetAttrString(enum_mod, "IntEnum");
+
+    Py_DECREF(enum_mod);
+
+    if (class == NULL)
+        goto no_class;
+
+    /* Compléments des paramètres */
+
+    str_obj = PyUnicode_FromString(doc);
+    ret = PyDict_SetItemString(values, "__doc__", str_obj);
+    Py_DECREF(str_obj);
+
+    if (ret != 0)
+        goto doc_error;
+
+    args = PyTuple_New(2);
+
+    ret = PyTuple_SetItem(args, 0, PyUnicode_FromString(name));
+    if (ret != 0) goto args_error;
+
+    Py_INCREF(values);
+    ret = PyTuple_SetItem(args, 1, values);
+    if (ret != 0) goto args_error;
+
+    kwargs = PyDict_New();
+
+    str_obj = PyUnicode_FromString(owner->tp_name);
+    ret = PyDict_SetItemString(kwargs, "module", str_obj);
+    Py_DECREF(str_obj);
+
+    if (ret != 0) goto kwargs_error;
+
+    /* Constitution de l'énumération et enregistrement */
+
+    new = PyObject_Call(class, args, kwargs);
+    if (new == NULL) goto build_error;
+
+    ret = PyDict_SetItemString(owner->tp_dict, name, new);
+    if (ret != 0) goto register_0_error;
+
+    features = get_access_to_python_module("pychrysalide.features");
+
+    features_dict = PyModule_GetDict(features);
+
+    ret = PyDict_SetItemString(features_dict, name, new);
+    if (ret != 0) goto register_1_error;
+
+    result = true;
+
+    /* Sortie propre */
+
+ register_1_error:
+ register_0_error:
+
+    Py_DECREF(new);
+
+ build_error:
+ kwargs_error:
+
+    Py_DECREF(kwargs);
+
+ args_error:
+
+    Py_DECREF(args);
+
+ doc_error:
+
+    Py_DECREF(class);
+
+ no_class:
+ no_mod:
+
+    Py_DECREF(values);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : owner = propriétaire du groupe de constantes.                *
+*                name  = désignation humaine du groupe à consulter.           *
+*                value = valeur à transmettre à Python.                       *
+*                                                                             *
+*  Description : Traduit une valeur constante C en équivalent Python.         *
+*                                                                             *
+*  Retour      : Objet Python résultant ou NULL en cas d'erreur.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyObject *cast_with_constants_group(const PyTypeObject *owner, const char *name, unsigned long value)
+{
+    PyObject *result;                       /* Objet Python à retourner    */
+    char *dot;                              /* Position du dernier point   */
+    char *modname;                          /* Chemin d'accès au module    */
+    PyObject *module;                       /* Module à consulter          */
+    PyObject *type;                         /* Classe propriétaire         */
+    PyObject *class;                        /* Classe "Enum*"              */
+    PyObject *args;                         /* Arguments de la construction*/
+
+    result = NULL;
+
+    /* Recherche de la classe Python */
+
+    dot = strrchr(owner->tp_name, '.');
+    assert(dot != NULL);
+
+    modname = strndup(owner->tp_name, dot - owner->tp_name);
+
+    module = get_access_to_python_module(modname);
+
+    if (module == NULL)
+        goto no_mod;
+
+    type = PyObject_GetAttrString(module, dot + 1);
+
+    if (type == NULL)
+        goto no_type;
+
+    class = PyObject_GetAttrString(type, name);
+
+    if (class == NULL)
+        goto no_class;
+
+    /* Construction */
+
+    args = Py_BuildValue("(k)", value);
+
+    result = PyObject_CallObject(class, args);
+
+    Py_DECREF(args);
+
+    Py_DECREF(class);
+
+ no_class:
+
+    Py_DECREF(type);
+
+ no_type:
+ no_mod:
+
+    free(modname);
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index 4ffb447..e2ebfbc 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -156,4 +156,33 @@ bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *)
 
 
 
+/* ----------------------- TRANSFERT DES VALEURS CONSTANTES ------------------------- */
+
+
+/* Officialise un groupe de constantes avec sémentique. */
+bool attach_constants_group(PyTypeObject *, bool, const char *, PyObject *, const char *);
+
+/* Simplification d'un ajout de constante pour l'appelant */
+#define add_const_to_group(d, n, v)                         \
+    ({                                                      \
+        bool __result;                                      \
+        PyObject *__val;                                    \
+        int __ret;                                          \
+        __val = PyLong_FromUnsignedLong(v);                 \
+        if (__val == NULL)                                  \
+            __result = false;                               \
+        else                                                \
+        {                                                   \
+            __ret = PyDict_SetItemString(d, n, __val);      \
+            Py_DECREF(__val);                               \
+            __result = (__ret == 0);                        \
+        }                                                   \
+        __result;                                           \
+    })
+
+/* Traduit une valeur constante C en équivalent Python. */
+PyObject *cast_with_constants_group(const PyTypeObject *, const char *, unsigned long);
+
+
+
 #endif  /* _PLUGINS_PYCHRYSALIDE_HELPERS_H */
diff --git a/tests/format/symbol.py b/tests/format/symbol.py
new file mode 100644
index 0000000..c720256
--- /dev/null
+++ b/tests/format/symbol.py
@@ -0,0 +1,26 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+# Tests pour valider la gestion des symboles
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.arch import vmpa, mrange
+from pychrysalide.format import BinSymbol
+
+
+class TestBinarySymbols(ChrysalideTestCase):
+    """TestCase for format.BinSymbol."""
+
+
+    def testSymbolDefaultStatus(self):
+        """Validate the default status for symbols."""
+
+        saddr = vmpa(0x10, vmpa.VMPA_NO_VIRTUAL)
+        srange = mrange(saddr, 0x3)
+        symbol = BinSymbol(BinSymbol.STP_ENTRY_POINT, srange)
+
+        self.assertEqual(symbol.status, BinSymbol.SymbolStatus.INTERNAL)
+
+        self.assertEqual(str(symbol.status), 'SymbolStatus.INTERNAL')
-- 
cgit v0.11.2-87-g4458