From 7cb4e815b691d05d8c0aea9decf56b9dbc41dfa6 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard 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 + + +#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 +#include + + + +/* 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 +#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