From 55ccf25e0c6666436f0ecd222e60208ebf6ab30e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 4 Jan 2019 00:36:47 +0100 Subject: Defined a dynamic type for each plugin. --- plugins/arm/core.c | 2 +- plugins/dalvik/core.c | 2 +- plugins/devdbg/speed.c | 2 +- plugins/dex/core.c | 2 +- plugins/dexbnf/core.c | 2 +- plugins/dwarf/core.c | 2 +- plugins/elf/core.c | 2 +- plugins/itanium/core.c | 2 +- plugins/javadesc/core.c | 2 +- plugins/libcsem/semantic.c | 2 +- plugins/lnxsyscalls/core.c | 2 +- plugins/mobicore/core.c | 2 +- plugins/pychrysalide/Makefile.am | 1 - plugins/pychrysalide/arch/processor.c | 39 +- plugins/pychrysalide/dt.c | 469 -------------- plugins/pychrysalide/dt.h | 47 -- plugins/pychrysalide/gui/editem.c | 3 - plugins/pychrysalide/gui/panels/panel.c | 39 +- plugins/pychrysalide/helpers.c | 74 +++ plugins/pychrysalide/helpers.h | 12 +- plugins/pychrysalide/plugin.c | 1041 ++++++++++++++++++------------- plugins/pychrysalide/pychrysa.c | 5 +- plugins/readdex/reader.c | 2 +- plugins/readelf/reader.c | 2 +- plugins/readmc/reader.c | 2 +- plugins/ropgadgets/plugin.c | 2 +- src/core/core.c | 5 + src/plugins/Makefile.am | 1 + src/plugins/dt.c | 474 ++++++++++++++ src/plugins/dt.h | 47 ++ src/plugins/plugin-def.h | 13 +- src/plugins/plugin-int.h | 16 +- src/plugins/plugin.c | 396 ++++++++++-- src/plugins/plugin.h | 12 +- tests/plugins/__init__.py | 0 tests/plugins/plugin.py | 223 +++++++ 36 files changed, 1824 insertions(+), 1125 deletions(-) delete mode 100644 plugins/pychrysalide/dt.c delete mode 100644 plugins/pychrysalide/dt.h create mode 100644 src/plugins/dt.c create mode 100644 src/plugins/dt.h create mode 100644 tests/plugins/__init__.py create mode 100644 tests/plugins/plugin.py diff --git a/plugins/arm/core.c b/plugins/arm/core.c index d2dd805..07b9b24 100644 --- a/plugins/arm/core.c +++ b/plugins/arm/core.c @@ -32,7 +32,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("arm", "Add support for the ARM architecture", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GArmPlugin", "arm", "Add support for the ARM architecture", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT)); diff --git a/plugins/dalvik/core.c b/plugins/dalvik/core.c index 2e936b9..d7e5a04 100644 --- a/plugins/dalvik/core.c +++ b/plugins/dalvik/core.c @@ -35,7 +35,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("dalvik", "Add support for the Dalvik architecture", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GDalvikPlugin", "dalvik", "Add support for the Dalvik architecture", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT)); diff --git a/plugins/devdbg/speed.c b/plugins/devdbg/speed.c index 935fbd9..77c407a 100644 --- a/plugins/devdbg/speed.c +++ b/plugins/devdbg/speed.c @@ -38,7 +38,7 @@ -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("Speed Measure", "Tracks to time spent for disassembling code", "0.1.0", +DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("GSpeedPlugin", "Speed Measure", "Tracks to time spent for disassembling code", "0.1.0", PGA_FORMAT_ANALYSIS_STARTED,PGA_FORMAT_ANALYSIS_ENDED, PGA_FORMAT_POST_ANALYSIS_STARTED, PGA_FORMAT_POST_ANALYSIS_ENDED, PGA_DISASSEMBLY_STARTED, PGA_DISASSEMBLY_ENDED); diff --git a/plugins/dex/core.c b/plugins/dex/core.c index 6bdb9d5..3e5b835 100644 --- a/plugins/dex/core.c +++ b/plugins/dex/core.c @@ -33,7 +33,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("dex", "Add support for the DEX format", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GDexPlugin", "dex", "Add support for the DEX format", "0.1.0", RL("PyChrysalide", "dexbnf"), AL(PGA_PLUGIN_INIT, PGA_CONTENT_RESOLVER)); diff --git a/plugins/dexbnf/core.c b/plugins/dexbnf/core.c index 774e88e..736fa5f 100644 --- a/plugins/dexbnf/core.c +++ b/plugins/dexbnf/core.c @@ -33,7 +33,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("dexbnf", "Symbol demangler for Dex", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GDexBnfPlugin", "dexbnf", "Symbol demangler for Dex", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); diff --git a/plugins/dwarf/core.c b/plugins/dwarf/core.c index fa7e0ec..1e2d900 100644 --- a/plugins/dwarf/core.c +++ b/plugins/dwarf/core.c @@ -31,7 +31,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("dwarf", "Add support for the DWARF format", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GDwarfPlugin", "dwarf", "Add support for the DWARF format", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT, PGA_FORMAT_ATTACH_DEBUG)); diff --git a/plugins/elf/core.c b/plugins/elf/core.c index 6b7810e..d3d226e 100644 --- a/plugins/elf/core.c +++ b/plugins/elf/core.c @@ -33,7 +33,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("elf", "Add support for the ELF format", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GElfPlugin", "elf", "Add support for the ELF format", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT, PGA_CONTENT_RESOLVER)); diff --git a/plugins/itanium/core.c b/plugins/itanium/core.c index ecfd7f0..71816f7 100644 --- a/plugins/itanium/core.c +++ b/plugins/itanium/core.c @@ -33,7 +33,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("itanium", "Symbol demangler for Itanium", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GItaniumPlugin", "itanium", "Symbol demangler for Itanium", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); diff --git a/plugins/javadesc/core.c b/plugins/javadesc/core.c index e374749..41c4789 100644 --- a/plugins/javadesc/core.c +++ b/plugins/javadesc/core.c @@ -33,7 +33,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("javadesc", "Symbol demangler for Java", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GJavaDescPlugin", "javadesc", "Symbol demangler for Java", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); diff --git a/plugins/libcsem/semantic.c b/plugins/libcsem/semantic.c index 0dc330e..de87012 100644 --- a/plugins/libcsem/semantic.c +++ b/plugins/libcsem/semantic.c @@ -32,7 +32,7 @@ -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("LibC semantics", "Register semantic information relative to the libc", "0.1.0", +DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("GCSemPlugin", "LibC semantics", "Register semantic information relative to the libc", "0.1.0", PGA_DISASSEMBLY_HOOKED_POST); diff --git a/plugins/lnxsyscalls/core.c b/plugins/lnxsyscalls/core.c index f28e776..cd9fa0e 100644 --- a/plugins/lnxsyscalls/core.c +++ b/plugins/lnxsyscalls/core.c @@ -37,7 +37,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("Linux System Calls", "Describes each Linux system call with its arguments", \ +DEFINE_CHRYSALIDE_PLUGIN("GLnxSyscallsPlugin", "Linux System Calls", "Describes each Linux system call with its arguments", \ "0.1.0", EMPTY_PG_LIST(.required), AL(PGA_PLUGIN_INIT, PGA_DISASSEMBLY_ENDED)); diff --git a/plugins/mobicore/core.c b/plugins/mobicore/core.c index bc7298f..9de116d 100644 --- a/plugins/mobicore/core.c +++ b/plugins/mobicore/core.c @@ -32,7 +32,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("mobicore", "Support MobiCore file format for Trusted Applications", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GMobicorePlugin", "mobicore", "Support MobiCore file format for Trusted Applications", "0.1.0", EMPTY_PG_LIST(.required), AL(PGA_CONTENT_RESOLVER)); diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am index 3fe13af..d9194b9 100644 --- a/plugins/pychrysalide/Makefile.am +++ b/plugins/pychrysalide/Makefile.am @@ -7,7 +7,6 @@ libdir = $(pluginslibdir) pychrysalide_la_SOURCES = \ access.h access.c \ constval.h constval.c \ - dt.h dt.c \ helpers.h helpers.c \ plugin.h plugin.c \ pychrysa.h pychrysa.c \ diff --git a/plugins/pychrysalide/arch/processor.c b/plugins/pychrysalide/arch/processor.c index 115f980..4feaa8b 100644 --- a/plugins/pychrysalide/arch/processor.c +++ b/plugins/pychrysalide/arch/processor.c @@ -31,6 +31,7 @@ #include #include +#include #include "context.h" @@ -38,7 +39,6 @@ #include "instruction.h" #include "vmpa.h" #include "../access.h" -#include "../dt.h" #include "../helpers.h" #include "../analysis/content.h" #include "../format/executable.h" @@ -140,18 +140,16 @@ static bool define_python_arch_processor_constants(PyTypeObject *); static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Objet à retourner */ - bool abstract; /* Validation du type parent */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ GType gtype; /* Nouveau type de processeur */ - PyObject *sys_mod_dict; /* Dictionnaire des modules */ - PyObject *modname; /* Nom du module du type */ - PyObject *module; /* Module à recompléter */ - PyObject *dict; /* Dictionnaire dudit module */ + bool status; /* Bilan d'un enregistrement */ /* Validations diverses */ - abstract = (type == get_python_arch_processor_type()); + base = get_python_arch_processor_type(); - if (abstract) + if (type == base) { result = NULL; PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); @@ -160,30 +158,23 @@ static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObj /* Mise en place d'un type dédié */ - gtype = built_dynamic_type(G_TYPE_ARCH_PROCESSOR, type->tp_name, - (GClassInitFunc)py_arch_processor_init_gclass); - - /* Enregistrement du nouveau GType dans Python */ - - sys_mod_dict = PyImport_GetModuleDict(); + first_time = (g_type_from_name(type->tp_name) == 0); - modname = PyDict_GetItemString(type->tp_dict, "__module__"); - - module = PyObject_GetItem(sys_mod_dict, modname); + gtype = built_dynamic_type(G_TYPE_ARCH_PROCESSOR, type->tp_name, + (GClassInitFunc)py_arch_processor_init_gclass, NULL); - dict = PyModule_GetDict(module); + if (first_time) + status = register_class_for_dynamic_pygobject(gtype, type, base); + else + status = true; - if (!_register_class_for_pygobject(dict, gtype, type, - &PyGObject_Type, get_python_arch_processor_type(), NULL)) + if (!status) { result = NULL; goto exit; } - Py_DECREF(module); - Py_DECREF(modname); - - /* On créé, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ result = PyType_GenericNew(type, args, kwds); diff --git a/plugins/pychrysalide/dt.c b/plugins/pychrysalide/dt.c deleted file mode 100644 index 0b46b45..0000000 --- a/plugins/pychrysalide/dt.c +++ /dev/null @@ -1,469 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * dt.c - possibilité de créer de nouveaux types de façon dynamique - * - * 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 Chrysalide. If not, see . - */ - - -#include "dt.h" - - -#include -#include - - - -/* ------------------------- MODULE DE GESTION DES NOUVEAUX ------------------------- */ - - -#define G_TYPE_DYNAMIC_TYPES g_dynamic_types_get_type() -#define G_DYNAMIC_TYPES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DYNAMIC_TYPES, GDynamicTypes)) -#define G_IS_DYNAMIC_TYPES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DYNAMIC_TYPES)) -#define G_DYNAMIC_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DYNAMIC_TYPES, GDynamicTypesClass)) -#define G_IS_DYNAMIC_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DYNAMIC_TYPES)) -#define G_DYNAMIC_TYPES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DYNAMIC_TYPES, GDynamicTypesClass)) - - -/* Mémorisation des caractéristiques de type */ -typedef struct _type_dyn_info_t -{ - GType type; /* Identifiant unique obtenu */ - GClassInitFunc init; /* Définition des méthodes */ - -} type_dyn_info_t; - -/* Description de fichier binaire (instance) */ -typedef struct _GDynamicTypes -{ - GObject parent; /* A laisser en premier */ - - type_dyn_info_t **info; /* Liste d'informations utiles */ - size_t count; /* Taille de cette liste */ - -} GDynamicTypes; - -/* Description de fichier binaire (classe) */ -typedef struct _GDynamicTypesClass -{ - GObjectClass parent; /* A laisser en premier */ - -} GDynamicTypesClass; - - -/* Indique le type défini pour une gestion de types dynamique. */ -static GType g_dynamic_types_get_type(void); - -/* Initialise la classe de gestion de types dynamique. */ -static void g_dynamic_types_class_init(GDynamicTypesClass *); - -/* Initialise une gestion de types dynamique. */ -static void g_dynamic_types_init(GDynamicTypes *); - -/* Procède à l'initialisation de l'interface de typage nouveau. */ -static void g_dynamic_types_interface_init(GTypePluginClass *); - -/* Supprime toutes les références externes. */ -static void g_dynamic_types_dispose(GDynamicTypes *); - -/* Procède à la libération totale de la mémoire. */ -static void g_dynamic_types_finalize(GDynamicTypes *); - -/* Crée un nouveau gestionnaire de nouveaux types. */ -static GDynamicTypes *g_dynamic_types_new(void); - -/* Marque une augmentation des utilisations. */ -static void g_dynamic_types_use(GDynamicTypes *); - -/* Marque une diminution des utilisations. */ -static void g_dynamic_types_unuse(GDynamicTypes *); - -/* Complète la définition d'un type dynamiquement. */ -static void g_dynamic_types_complete_type(GDynamicTypes *, GType, GTypeInfo *, GTypeValueTable *); - -/* Retrouve les informations concernant un type dynamique. */ -static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *, GType); - -/* Fournit un identifiant GLib pour un nouveau type Python. */ -static GType g_dynamic_types_register_type(GDynamicTypes *, GType, const char *, GClassInitFunc); - - - -/* ----------------------- ACCOMPAGNEMENTS DES NOUVEAUX TYPES ----------------------- */ - - -/* Encadrement des nouveaux types Python dérivés */ -static GDynamicTypes *_python_dtypes = NULL; - - - -/* ---------------------------------------------------------------------------------- */ -/* MODULE DE GESTION DES NOUVEAUX */ -/* ---------------------------------------------------------------------------------- */ - -/* Indique le type défini pour une gestion de types dynamique. */ -G_DEFINE_TYPE_WITH_CODE(GDynamicTypes, g_dynamic_types, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(G_TYPE_TYPE_PLUGIN, g_dynamic_types_interface_init)); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe de gestion de types dynamique. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_class_init(GDynamicTypesClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_dynamic_types_dispose; - object->finalize = (GObjectFinalizeFunc)g_dynamic_types_finalize; - -} - - -/****************************************************************************** -* * -* Paramètres : types = instance à initialiser. * -* * -* Description : Initialise une gestion de types dynamique. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_init(GDynamicTypes *types) -{ - -} - -/****************************************************************************** -* * -* Paramètres : iface = interface GLib à initialiser. * -* * -* Description : Procède à l'initialisation de l'interface de typage nouveau. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_interface_init(GTypePluginClass *iface) -{ - iface->use_plugin = (GTypePluginUse)g_dynamic_types_use; - iface->unuse_plugin = (GTypePluginUnuse)g_dynamic_types_unuse; - iface->complete_type_info = (GTypePluginCompleteTypeInfo)g_dynamic_types_complete_type; - -} - -/****************************************************************************** -* * -* Paramètres : types = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_dispose(GDynamicTypes *types) -{ - G_OBJECT_CLASS(g_dynamic_types_parent_class)->dispose(G_OBJECT(types)); - -} - - -/****************************************************************************** -* * -* Paramètres : types = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_finalize(GDynamicTypes *types) -{ - G_OBJECT_CLASS(g_dynamic_types_parent_class)->finalize(G_OBJECT(types)); - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Crée un nouveau gestionnaire de nouveaux types. * -* * -* Retour : Instance mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GDynamicTypes *g_dynamic_types_new(void) -{ - GDynamicTypes *result; /* Adresse à retourner */ - - result = g_object_new(G_TYPE_DYNAMIC_TYPES, NULL); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : types = gestionnaire de types courant. * -* * -* Description : Marque une augmentation des utilisations. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_use(GDynamicTypes *types) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : types = gestionnaire de types courant. * -* * -* Description : Marque une diminution des utilisations. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_unuse(GDynamicTypes *types) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : types = gestionnaire de types courant. * -* type = nouveau type GLib à traiter. * -* info = information concernant ce type à constituer. [OUT] * -* table = table de valeur à éventuellement initialiser. [OUT] * -* * -* Description : Complète la définition d'un type dynamiquement. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dynamic_types_complete_type(GDynamicTypes *types, GType type, GTypeInfo *info, GTypeValueTable *table) -{ - const type_dyn_info_t *nfo; /* Source d'inspiration */ - GType parent; /* Type parent du type */ - GTypeQuery query; /* Informations complémentaires*/ - - /* Consultation */ - - nfo = g_dynamic_types_find(types, type); - assert(nfo != NULL); - - parent = g_type_parent(type); - g_type_query(parent, &query); - - /* Définition */ - - info->class_size = query.class_size; - info->class_init = nfo->init; - - info->instance_size = query.instance_size; - -} - - -/****************************************************************************** -* * -* Paramètres : parent = type GLib parent. * -* type = identifiant du type GLib à considérer. * -* * -* Description : Retrouve les informations concernant un type dynamique. * -* * -* Retour : Structure contenant les informations associées au type. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, GType target) -{ - type_dyn_info_t *result; /* Informations à retourner */ - size_t i; /* Boucle de parcours */ - - result = NULL; - - for (i = 0; i < types->count && result == NULL; i++) - if (types->info[i]->type == target) - result = types->info[i]; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : parent = type GLib parent. * -* name = désignation du nouveau type. * -* init = procédure d'initialisation de la classe associée. * -* * -* Description : Fournit un identifiant GLib pour un nouveau type Python. * -* * -* Retour : identifiant d'un nouveau type valide, ou 0. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, const char *name, GClassInitFunc init) -{ - GType result; /* Identifiant à retourner */ - type_dyn_info_t *new; /* Mémorisation de paramètres */ - - /* Création d'un nouveau type adapté */ - - result = g_type_register_dynamic(parent, name, G_TYPE_PLUGIN(types), 0); - - if (result == 0) - goto exit; - - new = malloc(sizeof(type_dyn_info_t)); - - new->type = result; - new->init = init; - - /* Inscription définitive */ - - types->info = realloc(types->info, ++types->count * sizeof(type_dyn_info_t *)); - - types->info[types->count - 1] = new; - - exit: - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* ACCOMPAGNEMENTS DES NOUVEAUX TYPES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Lance le support de dérivations de types dans Python. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool init_dynamic_python_types(void) -{ - bool result; /* Bilan à retourner */ - - _python_dtypes = g_dynamic_types_new(); - - result = (_python_dtypes != NULL); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Arrête le support de dérivations de types dans Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void exit_dynamic_python_types(void) -{ - g_object_unref(G_OBJECT(_python_dtypes)); - -} - - -/****************************************************************************** -* * -* Paramètres : parent = type GLib parent. * -* name = désignation du nouveau type. * -* init = procédure d'initialisation de la classe associée. * -* * -* Retour : Identifiant d'un nouveau type valide, ou 0. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -GType built_dynamic_type(GType parent, const char *name, GClassInitFunc init) -{ - GType result; /* Identifiant à retourner */ - - result = g_type_from_name(name); - - if (result == 0) - result = g_dynamic_types_register_type(_python_dtypes, parent, name, init); - - return result; - -} diff --git a/plugins/pychrysalide/dt.h b/plugins/pychrysalide/dt.h deleted file mode 100644 index b0f16db..0000000 --- a/plugins/pychrysalide/dt.h +++ /dev/null @@ -1,47 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * dt.h - prototypes pour la possibilité de créer de nouveaux types de façon dynamique - * - * 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 Chrysalide. If not, see . - */ - - -#ifndef _PLUGINS_PYCHRYSALIDE_DT_H -#define _PLUGINS_PYCHRYSALIDE_DT_H - - -#include -#include - - - -/* ----------------------- ACCOMPAGNEMENTS DES NOUVEAUX TYPES ----------------------- */ - - -/* Lance le support de dérivations de types dans Python. */ -bool init_dynamic_python_types(void); - -/* Arrête le support de dérivations de types dans Python. */ -void exit_dynamic_python_types(void); - -/* Fournit un identifiant GLib pour un nouveau type Python. */ -GType built_dynamic_type(GType, const char *, GClassInitFunc); - - - -#endif /* _PLUGINS_PYCHRYSALIDE_DT_H */ diff --git a/plugins/pychrysalide/gui/editem.c b/plugins/pychrysalide/gui/editem.c index 986d1cb..68962ae 100644 --- a/plugins/pychrysalide/gui/editem.c +++ b/plugins/pychrysalide/gui/editem.c @@ -45,9 +45,6 @@ /* Réagit à un changement de contenu chargé en cours d'analyse. */ static void py_editor_item_change_content_wrapper(GEditorItem *, GLoadedContent *, GLoadedContent *); -/* Réagit à un changement de contenu chargé en cours d'analyse. */ -static void py_editor_item_change_content_wrapper(GEditorItem *, GLoadedContent *, GLoadedContent *); - /* Réagit à un changement de vue du contenu en cours d'analyse. */ static void py_editor_item_change_view_wrapper(GEditorItem *, GLoadedPanel *, GLoadedPanel *); diff --git a/plugins/pychrysalide/gui/panels/panel.c b/plugins/pychrysalide/gui/panels/panel.c index 1df0670..d4062d3 100644 --- a/plugins/pychrysalide/gui/panels/panel.c +++ b/plugins/pychrysalide/gui/panels/panel.c @@ -32,11 +32,11 @@ #include #include #include +#include #include "../editem.h" #include "../../access.h" -#include "../../dt.h" #include "../../helpers.h" #include "../../gtkext/dockable.h" @@ -89,18 +89,16 @@ static bool py_panel_item_define_constants(PyTypeObject *); static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result; /* Objet à retourner */ - bool abstract; /* Validation du type parent */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ GType gtype; /* Nouveau type de processeur */ - PyObject *sys_mod_dict; /* Dictionnaire des modules */ - PyObject *modname; /* Nom du module du type */ - PyObject *module; /* Module à recompléter */ - PyObject *dict; /* Dictionnaire dudit module */ + bool status; /* Bilan d'un enregistrement */ /* Validations diverses */ - abstract = (type == get_python_panel_item_type()); + base = get_python_panel_item_type(); - if (abstract) + if (type == base) { result = NULL; PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); @@ -109,30 +107,23 @@ static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject /* Mise en place d'un type dédié */ - gtype = built_dynamic_type(G_TYPE_PANEL_ITEM, type->tp_name, - (GClassInitFunc)py_panel_item_init_gclass); - - /* Enregistrement du nouveau GType dans Python */ - - sys_mod_dict = PyImport_GetModuleDict(); + first_time = (g_type_from_name(type->tp_name) == 0); - modname = PyDict_GetItemString(type->tp_dict, "__module__"); - - module = PyObject_GetItem(sys_mod_dict, modname); + gtype = built_dynamic_type(G_TYPE_PANEL_ITEM, type->tp_name, + (GClassInitFunc)py_panel_item_init_gclass, NULL); - dict = PyModule_GetDict(module); + if (first_time) + status = register_class_for_dynamic_pygobject(gtype, type, base); + else + status = true; - if (!_register_class_for_pygobject(dict, gtype, type, - &PyGObject_Type, get_python_panel_item_type(), NULL)) + if (!status) { result = NULL; goto exit; } - Py_DECREF(module); - Py_DECREF(modname); - - /* On créé, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ result = PyType_GenericNew(type, args, kwds); diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index ad62de4..a930097 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -701,3 +701,77 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty return result; } + + +/****************************************************************************** +* * +* Paramètres : dict = dictionnaire où conserver une référence au type créé.* +* gtype = type dans sa version GLib. * +* type = type dans sa version Python. * +* base = type de base de l'objet. * +* * +* Description : Enregistre un type Python dérivant d'un type GLib dynamique. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTypeObject *base) +{ + bool result; /* Bilan à retourner */ + PyTypeObject *legacy_parent; /* Type parent d'origine */ + PyObject *sys_mod_dict; /* Dictionnaire des modules */ + PyObject *modname; /* Nom du module du type */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire dudit module */ + + /** + * Lors de l'appel à pygobject_register_class(), PyGObject remplace systématiquement + * le type Python fourni par : + * + * Py_TYPE(type) = PyGObject_MetaType; + * + * Ce nouveau type est le suivant (cf. gi/types.py) : + * + * class _GObjectMetaBase(type): + * """Metaclass for automatically registering GObject classes.""" + * + * D'une part, comme les enregistrements sont gérés manuellement dans le cas de + * types dérivés dynamiquement d'objets natifs, ce changement est inutile. + * + * D'autre part, il semble avoir un soucis de références (cf. testGarbageCollecting() + * du fichier de test plugins/plugin.py) : + * + * python3dm: ../Modules/gcmodule.c:379: visit_decref: Assertion `_PyGCHead_REFS(gc) != 0' failed. + * + * #3 __GI___assert_fail () + * #4 visit_decref () + * #5 subtype_traverse () + * #6 subtract_refs () + * #7 collect () + * #8 collect_with_callback () + * #9 gc_collect () + * + * On restaure donc le type d'origine de l'objet Python créé dynamquement pour éviter + * ce genre de soucis. + */ + + legacy_parent = Py_TYPE(type); + + sys_mod_dict = PyImport_GetModuleDict(); + + modname = PyDict_GetItemString(type->tp_dict, "__module__"); + + module = PyObject_GetItem(sys_mod_dict, modname); + + dict = PyModule_GetDict(module); + + result = _register_class_for_pygobject(dict, gtype, type, &PyGObject_Type, base, NULL); + + Py_TYPE(type) = legacy_parent; + + return result; + +} diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index e080ca4..bf95e61 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -25,8 +25,9 @@ #define _PLUGINS_PYCHRYSALIDE_HELPERS_H -#include #include +#include +#include #include @@ -97,13 +98,8 @@ bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObje #define register_class_for_pygobject(dict, gtype, type, base) \ _register_class_for_pygobject(dict, gtype, type, base, NULL) - -/** - * Quand on remplace un objet GLib dans le dos de Python, il faut - * le remplacer de la même manière qu'on l'a obtenu ! - */ - -#define pygobject_set(p, v) ((PyGObject *)(p))->obj = (GObject *)v +/* Enregistre un type Python dérivant d'un type GLib dynamique. */ +bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *); diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c index a693d7b..22bfabb 100644 --- a/plugins/pychrysalide/plugin.c +++ b/plugins/pychrysalide/plugin.c @@ -32,6 +32,7 @@ #include +#include #include @@ -41,6 +42,50 @@ +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise la classe des greffons d'extension. */ +static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds); + +/* Valide les fonctionnalités déclarées en actions. */ +static bool py_plugin_module_check_interface(PyObject *); + +/* Accompagne la fin du chargement des modules natifs. */ +static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *, PluginAction); + +/* Complète une liste de resources pour thème. */ +static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, char ***, size_t *); + +/* Procède à une opération liée à un contenu binaire. */ +static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *); + +/* Procède à une opération liée à un contenu chargé. */ +static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *, PluginAction, GLoadedContent *, wgroup_id_t, GtkStatusStack *); + +/* Procède à une opération liée à l'analyse d'un format. */ +static bool py_plugin_module_handle_binary_format_analysis_wrapper(const GPluginModule *, PluginAction, GBinFormat *, wgroup_id_t, GtkStatusStack *); + +/* Procède à un préchargement de format de fichier. */ +static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *, PluginAction, GBinFormat *, GPreloadInfo *, GtkStatusStack *); + +/* Procède au rattachement d'éventuelles infos de débogage. */ +static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *, PluginAction, GExeFormat *); + +/* Exécute une action pendant un désassemblage de binaire. */ +static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *, PluginAction, GLoadedBinary *, GtkStatusStack *, GProcContext *); + +/* Effectue la détection d'effets d'outils externes. */ +static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *, PluginAction, const GLoadedContent *, bool, char ***, size_t *); + + + /* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ @@ -75,30 +120,6 @@ static void g_python_plugin_dispose(GPythonPlugin *); /* Description : Procède à la libération totale de la mémoire. */ static void g_python_plugin_finalize(GPythonPlugin *); -/* Reconstruit la déclaration d'interface à partir de lectures. */ -static bool g_python_plugin_read_interface(GPythonPlugin *); - -/* Procède à l'initialisation du greffon. */ -static bool g_python_plugin_do_init(GPythonPlugin *); - -/* Procède à l'extinction du greffon. */ -static bool g_python_plugin_do_exit(GPythonPlugin *); - -/* Procède à une opération liée à un contenu binaire. */ -static void g_python_plugin_handle_binary_content(const GPythonPlugin *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *); - -/* Procède à une opération liée à l'analyse d'un format. */ -static bool g_python_plugin_handle_binary_format_analysis(const GPythonPlugin *, PluginAction, GBinFormat *, wgroup_id_t, GtkStatusStack *); - -/* Procède à un préchargement de format de fichier. */ -static bool g_python_plugin_preload_binary_format(const GPythonPlugin *, PluginAction, GBinFormat *, GPreloadInfo *, GtkStatusStack *); - -/* Procède au rattachement d'éventuelles infos de débogage. */ -static void g_python_plugin_attach_debug_format(const GPythonPlugin *, PluginAction, GExeFormat *); - -/* Exécute une action pendant un désassemblage de binaire. */ -static void g_python_plugin_process_disass(const GPythonPlugin *, PluginAction, GLoadedBinary *, GtkStatusStack *, GProcContext *); - /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ @@ -113,61 +134,78 @@ static bool py_plugin_module_define_constants(PyTypeObject *); /* ---------------------------------------------------------------------------------- */ -/* INTERFACE INTERNE POUR GREFFONS PYTHON */ +/* GLUE POUR CREATION DEPUIS PYTHON */ /* ---------------------------------------------------------------------------------- */ -/* Indique le type défini par la GLib pour le greffon Python. */ -G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE); - - /****************************************************************************** * * -* Paramètres : klass = classe à initialiser. * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * * * -* Description : Initialise la classe des greffons Python. * +* Description : Accompagne la création d'une instance dérivée en Python. * * * -* Retour : - * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static void g_python_plugin_class_init(GPythonPluginClass *klass) +static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - GObjectClass *object; /* Autre version de la classe */ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ - object = G_OBJECT_CLASS(klass); + /* Validations diverses */ - object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; - object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; + base = get_python_plugin_module_type(); -} + if (type == base) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } + /* Mise en place d'un type dédié */ -/****************************************************************************** -* * -* Paramètres : plugin = instance à initialiser. * -* * -* Description : Initialise l'instance d'un greffon Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + first_time = (g_type_from_name(type->tp_name) == 0); -static void g_python_plugin_init(GPythonPlugin *plugin) -{ + gtype = built_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name, + (GClassInitFunc)py_plugin_module_init_gclass, NULL); + + if (first_time) + status = register_class_for_dynamic_pygobject(gtype, type, base); + else + status = true; + + if (!status) + { + result = NULL; + goto exit; + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; } /****************************************************************************** * * -* Paramètres : plugin = instance d'objet GLib à traiter. * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * * * -* Description : Supprime toutes les références externes. * +* Description : Initialise la classe des greffons d'extension. * * * * Retour : - * * * @@ -175,191 +213,147 @@ static void g_python_plugin_init(GPythonPlugin *plugin) * * ******************************************************************************/ -static void g_python_plugin_dispose(GPythonPlugin *plugin) +static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unused) { - PyThreadState *tstate; /* Contexte d'environnement */ + class->init = NULL; + class->exit = NULL; - /** - * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock - * - * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur, - * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante : - * - * Fatal Python error: drop_gil: GIL is not locked - * - * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée - * comme dépréciée depuis Python 3.2. - * - * Donc on choisit les alternatives officielles. - * - * Cependant, PyThreadState_Get() renvoit l'erreur suivante : - * - * Fatal Python error: PyThreadState_Get: no current thread - * - * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur - * est intégré dans l'éditeur. - */ + class->native_loaded = py_plugin_module_notify_native_loaded_wrapper; - tstate = get_pychrysalide_main_tstate(); + class->include_theme = py_plugin_module_include_theme_wrapper; - if (tstate != NULL) - PyEval_RestoreThread(tstate); + class->handle_content = py_plugin_module_handle_binary_content_wrapper; + class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper; - Py_XDECREF(plugin->instance); - plugin->instance = NULL; + class->handle_fmt_analysis = py_plugin_module_handle_binary_format_analysis_wrapper; + class->preload_format = py_plugin_module_preload_binary_format_wrapper; + class->attach_debug = py_plugin_module_attach_debug_format_wrapper; - if (tstate != NULL) - PyEval_SaveThread(); + class->process_disass = py_plugin_module_process_disassembly_event_wrapper; - G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); + class->detect = py_plugin_module_detect_external_tools_wrapper; } /****************************************************************************** * * -* Paramètres : plugin = instance d'objet GLib à traiter. * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Procède à la libération totale de la mémoire. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : - * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static void g_python_plugin_finalize(GPythonPlugin *plugin) +static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds) { - plugin_interface *final; /* Interface finale conservée */ + const char *name; /* Désignation humaine courte */ + const char *desc; /* Description plus loquace */ + const char *version; /* Version du greffon */ + PyObject *actions_obj; /* Liste des actions offertes */ + int ret; /* Bilan de lecture des args. */ + PyObject *new_kwds; /* Nouveau dictionnaire épuré */ + GPluginModule *plugin; /* Greffon à manipuler */ + plugin_interface *iface; /* Interface à constituer */ + size_t i; /* Boucle de parcours */ + PyObject *action; /* Identifiant d'une action */ - Py_DECREF(plugin->module); + static char *kwlist[] = { "name", "desc", "version", "actions", NULL }; - final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; + /* Récupération des paramètres */ - if (final != NULL) - { - assert(final->required_count == 1); + ret = PyArg_ParseTupleAndKeywords(args, kwds, "sssO!", kwlist, + &name, &desc, &version, &PyTuple_Type, &actions_obj); + if (!ret) return -1; - free(final->required); - free(final); + /* Initialisation d'un objet GLib */ - } + new_kwds = PyDict_New(); - G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); + ret = PyGObject_Type.tp_init(self, args, new_kwds); -} + Py_DECREF(new_kwds); + if (ret == -1) return -1; -/****************************************************************************** -* * -* Paramètres : modname = nom du module à charger. * -* filename = chemin d'accès au code Python à charger. * -* * -* Description : Crée un greffon à partir de code Python. * -* * -* Retour : Adresse de la structure mise en place ou NULL si erreur. * -* * -* Remarques : - * -* * -******************************************************************************/ + /* Eléments de base */ -GPluginModule *g_python_plugin_new(const char *modname, const char *filename) -{ - GPythonPlugin *result; /* Structure à retourner */ - PyObject *name; /* Chemin d'accès pour Python */ - PyObject *module; /* Script Python chargé */ - PyObject *err_type; /* Type d'erreur Python */ - PyObject *err_value; /* Instance Python d'erreur */ - PyObject *err_traceback; /* Trace Python associée */ - PyObject *err_string; /* Description Python d'erreur */ - const char *err_msg; /* Représentation humaine */ - PyObject *dict; /* Dictionnaire associé */ - PyObject *class; /* Classe à instancier */ - PyObject *instance; /* Instance Python du greffon */ - size_t i; /* Boucle de parcours */ - uint32_t action; /* Identifiant d'une action */ - uint32_t category; /* Catégorie principale */ - uint32_t sub; /* Sous-catégorie visée */ + plugin = G_PLUGIN_MODULE(pygobject_get(self)); - name = PyUnicode_FromString(modname); - if (name == NULL) goto gppn_bad_exit; + iface = malloc(sizeof(plugin_interface)); + plugin->interface = iface; - module = PyImport_Import(name); - Py_DECREF(name); + iface->name = strdup(name); + iface->desc = strdup(desc); + iface->version = strdup(version); - if (PyErr_Occurred()) - { - PyErr_Fetch(&err_type, &err_value, &err_traceback); + iface->container = false; - if (err_value == NULL) - log_variadic_message(LMT_ERROR, - _("An unknown error occured when importing '%s'..."), modname); - else - { - err_string = PyObject_Str(err_value); - err_msg = PyUnicode_AsUTF8(err_string); + iface->required = malloc(sizeof(char *)); + iface->required[0] = "PyChrysalide"; + iface->required_count = 1; - log_variadic_message(LMT_ERROR, - _("An error occured when importing '%s': \"%s\""), modname, err_msg); + iface->actions_count = PyTuple_Size(actions_obj); + iface->actions = malloc(iface->actions_count * sizeof(plugin_action_t)); - Py_DECREF(err_string); - Py_DECREF(err_value); + for (i = 0; i < iface->actions_count; i++) + { + action = PyTuple_GetItem(actions_obj, i); + if (!PyLong_Check(action)) + { + PyErr_SetString(PyExc_TypeError, _("invalid type for plugin action.")); + return -1; } - Py_XDECREF(err_traceback); - Py_XDECREF(err_type); - - Py_XDECREF(module); + iface->actions[i] = PyLong_AsUnsignedLong(action); - module = NULL; + } + if (!py_plugin_module_check_interface(self)) + { + PyErr_SetString(PyExc_TypeError, _("missing features for the declared actions.")); + return -1; } - if (module == NULL) goto gppn_bad_exit; + return 0; - dict = PyModule_GetDict(module); - class = PyDict_GetItemString(dict, "AutoLoad"); +} - if (class == NULL) goto gppn_no_class; - if (!PyType_Check(class->ob_type)) goto gppn_no_class; - instance = PyObject_CallFunction(class, NULL); - if (instance == NULL) goto gppn_no_instance; +/****************************************************************************** +* * +* Paramètres : self = greffon Python en cours d'initialisation. * +* * +* Description : Valide les fonctionnalités déclarées en actions. * +* * +* Retour : true si le greffon Python est à priori utilisable. * +* * +* Remarques : - * +* * +******************************************************************************/ - result = g_object_new(G_TYPE_PYTHON_PLUGIN, NULL); +static bool py_plugin_module_check_interface(PyObject *self) +{ + bool result; /* Bilan à retourner */ + GPluginModule *plugin; /* Greffon à manipuler */ + size_t i; /* Boucle de parcours */ + uint32_t action; /* Identifiant d'une action */ + uint32_t category; /* Catégorie principale */ + uint32_t sub; /* Sous-catégorie visée */ - G_PLUGIN_MODULE(result)->filename = strdup(filename); + result = true; - result->module = module; - result->instance = instance; + plugin = G_PLUGIN_MODULE(pygobject_get(self)); - if (!g_python_plugin_read_interface(result)) - goto gppn_interface_error; - - /* Localisation des différents points d'entrée déclarés */ - -#define register_python_binding(inst, pysym, sym, binding) \ - ({ \ - bool __result; \ - if (!has_python_method(inst, #pysym)) \ - { \ - log_variadic_message(LMT_ERROR, \ - _("No '%s' entry in plugin candidate '%s'"), \ - #pysym, G_PLUGIN_MODULE(result)->filename); \ - __result = false; \ - } \ - else \ - { \ - G_PLUGIN_MODULE(result)->sym = binding; \ - __result = true; \ - } \ - __result; \ - }) - - for (i = 0; i < G_PLUGIN_MODULE(result)->interface->actions_count; i++) + for (i = 0; i < plugin->interface->actions_count && result; i++) { - action = G_PLUGIN_MODULE(result)->interface->actions[i]; + action = plugin->interface->actions[i]; category = MASK_PLUGIN_CATEGORY(action); sub = MASK_PLUGIN_SUB_CATEGORY(action); @@ -373,20 +367,17 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) break; case PGA_PLUGIN_INIT: - if (!register_python_binding(instance, init, init, - (pg_management_fc)g_python_plugin_do_init)) - goto gppn_bad_plugin; + result = has_python_method(self, "init"); break; case PGA_PLUGIN_EXIT: - if (!register_python_binding(instance, exit, exit, - (pg_management_fc)g_python_plugin_do_exit)) - goto gppn_bad_plugin; + result = has_python_method(self, "exit"); break; default: log_variadic_message(LMT_WARNING, - _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); + _("Unknown sub-category '0x%02x' in plugin '%s'..."), + sub, self->ob_type->tp_name); break; } @@ -402,16 +393,17 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) switch (action) { case PGA_CONTENT_EXPLORER: + result = has_python_method(self, "handle_binary_content"); + break; + case PGA_CONTENT_RESOLVER: - if (!register_python_binding(instance, handle_content, handle_content, - (pg_handle_content_fc)g_python_plugin_handle_binary_content)) - goto gppn_bad_plugin; + result = has_python_method(self, "handle_loaded_content"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - action, filename); + action, self->ob_type->tp_name); break; } @@ -426,27 +418,21 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) case PGA_FORMAT_ANALYSIS_ENDED: case PGA_FORMAT_POST_ANALYSIS_STARTED: case PGA_FORMAT_POST_ANALYSIS_ENDED: - if (!register_python_binding(instance, handle_format_analysis, handle_fmt_analysis, - (pg_handle_format_analysis_fc)g_python_plugin_handle_binary_format_analysis)) - goto gppn_bad_plugin; + result = has_python_method(self, "handle_format_analysis"); break; case PGA_FORMAT_PRELOAD: - if (!register_python_binding(instance, preload_format, preload_format, - (pg_preload_format_fc)g_python_plugin_preload_binary_format)) - goto gppn_bad_plugin; + result = has_python_method(self, "preload_format"); break; case PGA_FORMAT_ATTACH_DEBUG: - if (!register_python_binding(instance, attach_debug_format, attach_debug, - (pg_attach_debug)g_python_plugin_attach_debug_format)) - goto gppn_bad_plugin; + result = has_python_method(self, "attach_debug_format"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - action, filename); + action, self->ob_type->tp_name); break; } @@ -454,14 +440,13 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) break; case DPS_DISASSEMBLY: - if (!register_python_binding(instance, process_disassembly, process_disass, - (pg_process_disassembly_fc)g_python_plugin_process_disass)) - goto gppn_bad_plugin; + result = has_python_method(self, "process_disassembly"); break; default: log_variadic_message(LMT_WARNING, - _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); + _("Unknown sub-category '0x%02x' in plugin '%s'..."), + sub, self->ob_type->tp_name); break; } @@ -470,230 +455,374 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) default: log_variadic_message(LMT_WARNING, - _("Unknown category '0x%02x' in plugin '%s'..."), category, filename); + _("Unknown category '0x%02x' in plugin '%s'..."), + category, self->ob_type->tp_name); break; } } - /* Conclusion */ + return result; - return G_PLUGIN_MODULE(result); +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* unused = variable non utilisé pour l'usage de __VA_ARGS__. * +* * +* Description : Accompagne la fin du chargement des modules natifs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - gppn_bad_plugin: +static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *plugin, PluginAction action) +{ - gppn_interface_error: +} - g_object_unref(G_OBJECT(result)); - return NULL; +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* resources = liste de ressources à constituer. [OUT] * +* count = taille de cette liste. [OUT] * +* * +* Description : Complète une liste de resources pour thème. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - gppn_no_instance: +static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, char ***resources, size_t *count) +{ - gppn_no_class: +} - Py_DECREF(module); - gppn_bad_exit: +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* content = contenu binaire à traiter. * +* wid = identifiant du groupe de traitement. * +* status = barre de statut à tenir informée. * +* * +* Description : Procède à une opération liée à un contenu binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ - return NULL; +static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + assert(has_python_method(pyobj, "handle_binary_content")); + + args = PyTuple_New(4); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); + PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid)); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); + + value = run_python_method(pyobj, "handle_binary_content", args); + + Py_XDECREF(value); + Py_DECREF(args); + + PyGILState_Release(gstate); } /****************************************************************************** * * -* Paramètres : plugin = greffon à initialiser. * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* content = contenu chargé à traiter. * +* wid = identifiant du groupe de traitement. * +* status = barre de statut à tenir informée. * * * -* Description : Reconstruit la déclaration d'interface à partir de lectures. * +* Description : Procède à une opération liée à un contenu chargé. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_python_plugin_read_interface(GPythonPlugin *plugin) +static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t wid, GtkStatusStack *status) { - bool result; /* Bilan à renvoyer */ - plugin_interface interface; /* Recueil des éléments */ - PyObject *desc; /* Tableau de description */ - PyObject *str; /* Chaîne de caractères */ - PyObject *tuple; /* Liste d'éléments à traiter */ - Py_ssize_t count; /* Nombre d'éléments présents */ - Py_ssize_t i; /* Boucle de parcours */ - PyObject *action; /* Identifiant d'une action */ - plugin_interface *final; /* Interface finale conservée */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ - result = true; + gstate = PyGILState_Ensure(); - desc = run_python_method(plugin->instance, "get_interface", NULL); - if (!PyDict_Check(desc)) - { - result = false; - goto pgpri_end; - } + pyobj = pygobject_new(G_OBJECT(plugin)); - memset(&interface, 0, sizeof(interface)); + assert(has_python_method(pyobj, "handle_loaded_content")); - /* Chargements des premières chaînes */ + args = PyTuple_New(4); -#define READ_STR_FIELD(name) \ - str = PyDict_GetItemString(desc, #name); \ - if ((result = PyUnicode_Check(str))) \ - interface.name = strdup(PyUnicode_DATA(str)); \ + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); + PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid)); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); - READ_STR_FIELD(name); - READ_STR_FIELD(desc); - READ_STR_FIELD(version); + value = run_python_method(pyobj, "handle_loaded_content", args); - /* Chargement des actions supportées */ + Py_XDECREF(value); + Py_DECREF(args); - tuple = PyDict_GetItemString(desc, "actions"); + PyGILState_Release(gstate); - if (!PyList_Check(tuple)) - { - result = false; - goto pgpri_failed; - } +} - count = PyList_GET_SIZE(tuple); - interface.actions = (plugin_action_t *)calloc(count, sizeof(plugin_action_t)); - interface.actions_count = count; +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* format = format de binaire à manipuler pendant l'opération. * +* gid = groupe de travail dédié. * +* status = barre de statut à tenir informée. * +* * +* Description : Procède à une opération liée à l'analyse d'un format. * +* * +* Retour : Bilan de l'exécution du traitement. * +* * +* Remarques : - * +* * +******************************************************************************/ - for (i = 0; i < count; i++) - { - action = PyList_GET_ITEM(tuple, i); +static bool py_plugin_module_handle_binary_format_analysis_wrapper(const GPluginModule *plugin, PluginAction action, GBinFormat *format, wgroup_id_t gid, GtkStatusStack *status) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ - interface.actions[i] = PyLong_AsUnsignedLong(action); + gstate = PyGILState_Ensure(); - } + pyobj = pygobject_new(G_OBJECT(plugin)); - pgpri_failed: + assert(has_python_method(pyobj, "handle_format_analysis")); - if (result) - { - final = (plugin_interface *)calloc(1, sizeof(plugin_interface)); + args = PyTuple_New(4); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); + PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid)); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); - memcpy(final, &interface, sizeof(interface)); + value = run_python_method(pyobj, "handle_format_analysis", args); - final->required = (const char **)malloc(sizeof(char *)); - final->required[0] = "PyChrysalide"; - final->required_count = 1; + Py_XDECREF(value); + Py_DECREF(args); - G_PLUGIN_MODULE(plugin)->interface = final; + PyGILState_Release(gstate); - } - else - { - if (interface.name != NULL) free((char *)interface.name); - if (interface.desc != NULL) free((char *)interface.desc); - if (interface.version != NULL) free((char *)interface.version); + return true; - if (interface.actions != NULL) free(interface.actions); +} - } - pgpri_end: +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* format = format de binaire à manipuler pendant l'opération. * +* info = informations à constituer en avance de phase. * +* status = barre de statut à tenir informée. * +* * +* Description : Procède à un préchargement de format de fichier. * +* * +* Retour : Bilan de l'exécution du traitement. * +* * +* Remarques : - * +* * +******************************************************************************/ - Py_XDECREF(desc); +static bool py_plugin_module_preload_binary_format_wrapper(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ - return result; + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + assert(has_python_method(pyobj, "preload_format")); + + args = PyTuple_New(4); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(info))); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); + + value = run_python_method(pyobj, "preload_format", args); + + Py_XDECREF(value); + Py_DECREF(args); + + PyGILState_Release(gstate); + + return true; } /****************************************************************************** * * -* Paramètres : plugin = greffon à initialiser. * -* ref = espace de référencement global. * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* format = format de binaire à manipuler pendant l'opération. * * * -* Description : Procède à l'initialisation du greffon. * +* Description : Procède au rattachement d'éventuelles infos de débogage. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_python_plugin_do_init(GPythonPlugin *plugin) +static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *plugin, PluginAction action, GExeFormat *format) { - bool result; /* Bilan à retourner */ - PyThreadState *tstate; /* Contexte d'environnement */ - PyObject *value; /* Valeur obtenue */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ + + gstate = PyGILState_Ensure(); - tstate = PyThreadState_Get(); + pyobj = pygobject_new(G_OBJECT(plugin)); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + assert(has_python_method(pyobj, "attach_debug_format")); - if (!has_python_method(plugin->instance, "init")) - result = true; + args = PyTuple_New(2); - else - { - value = run_python_method(plugin->instance, "init", NULL); + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); - result = (value != NULL && PyObject_IsTrue(value)); + value = run_python_method(pyobj, "attach_debug_format", args); - Py_XDECREF(value); + Py_XDECREF(value); + Py_DECREF(args); - } + PyGILState_Release(gstate); - if (tstate != NULL) - PyEval_SaveThread(); +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* binary = binaire dont le contenu est en cours de traitement. * +* status = barre de statut à tenir informée. * +* context = contexte de désassemblage. * +* * +* Description : Exécute une action pendant un désassemblage de binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_plugin_module_process_disassembly_event_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeurs obtenues */ + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + assert(has_python_method(pyobj, "process_disassembly")); + + args = PyTuple_New(4); + + PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(binary))); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(status))); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(context))); + + value = run_python_method(pyobj, "process_disassembly", args); - return result; + Py_XDECREF(value); + Py_DECREF(args); + + PyGILState_Release(gstate); } /****************************************************************************** * * -* Paramètres : plugin = greffon à initialiser. * +* Paramètres : plugin = greffon à manipuler. * +* action = type d'action attendue. * +* content = élément chargé à consulter. * +* version = précise si les versions doivent être recherchées. * +* names = désignations humaines correspondantes, à libérer. * +* count = nombre de types d'obscurcissement trouvés. [OUT] * * * -* Description : Procède à l'extinction du greffon. * +* Description : Effectue la détection d'effets d'outils externes. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_python_plugin_do_exit(GPythonPlugin *plugin) +static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count) { - bool result; /* Bilan à retourner */ - PyObject *value; /* Valeur obtenue */ - if (!has_python_method(plugin->instance, "exit")) - result = true; - - else - { - value = run_python_method(plugin->instance, "exit", NULL); +} - result = (value != NULL && PyObject_IsTrue(value)); - Py_XDECREF(value); - } +/* ---------------------------------------------------------------------------------- */ +/* INTERFACE INTERNE POUR GREFFONS PYTHON */ +/* ---------------------------------------------------------------------------------- */ - return result; -} +/* Indique le type défini par la GLib pour le greffon Python. */ +G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE); /****************************************************************************** * * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* content = contenu binaire à traiter. * -* wid = identifiant du groupe de traitement. * -* status = barre de statut à tenir informée. * +* Paramètres : klass = classe à initialiser. * * * -* Description : Procède à une opération liée à un contenu binaire. * +* Description : Initialise la classe des greffons Python. * * * * Retour : - * * * @@ -701,124 +830,94 @@ static bool g_python_plugin_do_exit(GPythonPlugin *plugin) * * ******************************************************************************/ -static void g_python_plugin_handle_binary_content(const GPythonPlugin *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status) +static void g_python_plugin_class_init(GPythonPluginClass *klass) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Valeurs obtenues */ - - gstate = PyGILState_Ensure(); - - args = PyTuple_New(4); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); - PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(wid)); - PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); - - value = run_python_method(plugin->instance, "handle_content", args); + GObjectClass *object; /* Autre version de la classe */ - Py_XDECREF(value); - Py_DECREF(args); + object = G_OBJECT_CLASS(klass); - PyGILState_Release(gstate); + object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; + object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; } /****************************************************************************** * * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* format = format de binaire à manipuler pendant l'opération. * -* gid = groupe de travail dédié. * -* status = barre de statut à tenir informée. * +* Paramètres : plugin = instance à initialiser. * * * -* Description : Procède à une opération liée à l'analyse d'un format. * +* Description : Initialise l'instance d'un greffon Python. * * * -* Retour : Bilan de l'exécution du traitement. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_python_plugin_handle_binary_format_analysis(const GPythonPlugin *plugin, PluginAction action, GBinFormat *format, wgroup_id_t gid, GtkStatusStack *status) +static void g_python_plugin_init(GPythonPlugin *plugin) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Valeurs obtenues */ - - gstate = PyGILState_Ensure(); - - args = PyTuple_New(4); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); - PyTuple_SetItem(args, 2, PyLong_FromUnsignedLong(gid)); - PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); - - value = run_python_method(plugin->instance, "handle_format_analysis", args); - - Py_XDECREF(value); - Py_DECREF(args); - - PyGILState_Release(gstate); - - return true; } /****************************************************************************** * * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* format = format de binaire à manipuler pendant l'opération. * -* info = informations à constituer en avance de phase. * -* status = barre de statut à tenir informée. * +* Paramètres : plugin = instance d'objet GLib à traiter. * * * -* Description : Procède à un préchargement de format de fichier. * +* Description : Supprime toutes les références externes. * * * -* Retour : Bilan de l'exécution du traitement. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_python_plugin_preload_binary_format(const GPythonPlugin *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status) +static void g_python_plugin_dispose(GPythonPlugin *plugin) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Valeurs obtenues */ - - gstate = PyGILState_Ensure(); + PyThreadState *tstate; /* Contexte d'environnement */ - args = PyTuple_New(4); + /** + * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock + * + * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur, + * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante : + * + * Fatal Python error: drop_gil: GIL is not locked + * + * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée + * comme dépréciée depuis Python 3.2. + * + * Donc on choisit les alternatives officielles. + * + * Cependant, PyThreadState_Get() renvoit l'erreur suivante : + * + * Fatal Python error: PyThreadState_Get: no current thread + * + * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur + * est intégré dans l'éditeur. + */ - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); - PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(info))); - PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); + tstate = get_pychrysalide_main_tstate(); - value = run_python_method(plugin->instance, "preload_format", args); + if (tstate != NULL) + PyEval_RestoreThread(tstate); - Py_XDECREF(value); - Py_DECREF(args); + Py_XDECREF(plugin->instance); + plugin->instance = NULL; - PyGILState_Release(gstate); + if (tstate != NULL) + PyEval_SaveThread(); - return true; + G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); } /****************************************************************************** * * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* format = format de binaire à manipuler pendant l'opération. * +* Paramètres : plugin = instance d'objet GLib à traiter. * * * -* Description : Procède au rattachement d'éventuelles infos de débogage. * +* Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * @@ -826,66 +925,121 @@ static bool g_python_plugin_preload_binary_format(const GPythonPlugin *plugin, P * * ******************************************************************************/ -static void g_python_plugin_attach_debug_format(const GPythonPlugin *plugin, PluginAction action, GExeFormat *format) +static void g_python_plugin_finalize(GPythonPlugin *plugin) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Valeurs obtenues */ + plugin_interface *final; /* Interface finale conservée */ - gstate = PyGILState_Ensure(); + Py_XDECREF(plugin->module); - args = PyTuple_New(2); + final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); + if (final != NULL) + { + assert(final->required_count == 1); + free(final->required); - value = run_python_method(plugin->instance, "attach_debug_format", args); + free(final); - Py_XDECREF(value); - Py_DECREF(args); + } - PyGILState_Release(gstate); + G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); } /****************************************************************************** * * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* binary = binaire dont le contenu est en cours de traitement.* -* status = barre de statut à tenir informée. * -* context = contexte de désassemblage. * +* Paramètres : modname = nom du module à charger. * +* filename = chemin d'accès au code Python à charger. * * * -* Description : Exécute une action pendant un désassemblage de binaire. * +* Description : Crée un greffon à partir de code Python. * * * -* Retour : - * +* Retour : Adresse de la structure mise en place ou NULL si erreur. * * * * Remarques : - * * * ******************************************************************************/ -static void g_python_plugin_process_disass(const GPythonPlugin *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context) +GPluginModule *g_python_plugin_new(const char *modname, const char *filename) { - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Valeurs obtenues */ + GPythonPlugin *result; /* Structure à retourner */ + PyObject *name; /* Chemin d'accès pour Python */ + PyObject *module; /* Script Python chargé */ + PyObject *err_type; /* Type d'erreur Python */ + PyObject *err_value; /* Instance Python d'erreur */ + PyObject *err_traceback; /* Trace Python associée */ + PyObject *err_string; /* Description Python d'erreur */ + const char *err_msg; /* Représentation humaine */ + PyObject *dict; /* Dictionnaire associé */ + PyObject *class; /* Classe à instancier */ + PyObject *instance; /* Instance Python du greffon */ - gstate = PyGILState_Ensure(); + name = PyUnicode_FromString(modname); + if (name == NULL) goto gppn_bad_exit; - args = PyTuple_New(4); + module = PyImport_Import(name); + Py_DECREF(name); - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(binary))); - PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(status))); - PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(context))); + if (PyErr_Occurred()) + { + PyErr_Fetch(&err_type, &err_value, &err_traceback); - value = run_python_method(plugin->instance, "process_disassembly", args); + if (err_value == NULL) + log_variadic_message(LMT_ERROR, + _("An unknown error occured when importing '%s'..."), modname); + else + { + err_string = PyObject_Str(err_value); + err_msg = PyUnicode_AsUTF8(err_string); - Py_XDECREF(value); - Py_DECREF(args); + log_variadic_message(LMT_ERROR, + _("An error occured when importing '%s': \"%s\""), modname, err_msg); - PyGILState_Release(gstate); + Py_DECREF(err_string); + Py_DECREF(err_value); + + } + + Py_XDECREF(err_traceback); + Py_XDECREF(err_type); + + Py_XDECREF(module); + + module = NULL; + + } + + if (module == NULL) goto gppn_bad_exit; + + dict = PyModule_GetDict(module); + class = PyDict_GetItemString(dict, "AutoLoad"); + + if (class == NULL) goto gppn_no_class; + if (!PyType_Check(class->ob_type)) goto gppn_no_class; + + instance = PyObject_CallFunction(class, NULL); + if (instance == NULL) goto gppn_no_instance; + + result = G_PYTHON_PLUGIN(pygobject_get(instance)); + + G_PLUGIN_MODULE(result)->filename = strdup(filename); + + result->module = module; + result->instance = instance; + + Py_INCREF(instance); + + return G_PLUGIN_MODULE(result); + + gppn_no_instance: + + gppn_no_class: + + Py_DECREF(module); + + gppn_bad_exit: + + return NULL; } @@ -926,7 +1080,7 @@ static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args) case LMT_BAD_BINARY: case LMT_ERROR: case LMT_EXT_ERROR: - /*g_plugin_module_*/log_simple_message(/*G_PLUGIN_MODULE(pygobject_get(self)), */type, msg); + g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg); result = Py_None; Py_INCREF(result); break; @@ -1037,7 +1191,10 @@ PyTypeObject *get_python_plugin_module_type(void) .tp_doc = "Chrysalide plugin for Python.", .tp_methods = py_plugin_module_methods, - .tp_getset = py_plugin_module_getseters + .tp_getset = py_plugin_module_getseters, + + .tp_init = py_plugin_module_init, + .tp_new = py_plugin_module_new, }; @@ -1072,7 +1229,7 @@ bool ensure_python_plugin_module_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type)) return false; if (!py_plugin_module_define_constants(type)) diff --git a/plugins/pychrysalide/pychrysa.c b/plugins/pychrysalide/pychrysa.c index 8849981..502bf20 100644 --- a/plugins/pychrysalide/pychrysa.c +++ b/plugins/pychrysalide/pychrysa.c @@ -45,7 +45,6 @@ #include "access.h" #include "constval.h" -#include "dt.h" #include "helpers.h" #include "plugin.h" #include "star.h" @@ -63,7 +62,7 @@ -DEFINE_CHRYSALIDE_CONTAINER_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", +DEFINE_CHRYSALIDE_CONTAINER_PLUGIN("GPyChrysalidePlugin", "PyChrysalide", "Provides bindings to Python", "0.1.0", EMPTY_PG_LIST(.required), AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT, PGA_NATIVE_LOADED)); @@ -368,8 +367,6 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) /* Mise en place des fonctionnalités offertes */ - init_dynamic_python_types(); - result = PyModule_Create(&py_chrysalide_module); register_access_to_python_module(py_chrysalide_module.m_name, result); diff --git a/plugins/readdex/reader.c b/plugins/readdex/reader.c index 5b84a0d..2009ad6 100644 --- a/plugins/readdex/reader.c +++ b/plugins/readdex/reader.c @@ -34,7 +34,7 @@ -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("readdex", "Displays information about DEX files", "0.2.0", +DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("GDexReaderPlugin", "readdex", "Displays information about DEX files", "0.2.0", PGA_FORMAT_PRELOAD); diff --git a/plugins/readelf/reader.c b/plugins/readelf/reader.c index b137659..ba4d17a 100644 --- a/plugins/readelf/reader.c +++ b/plugins/readelf/reader.c @@ -35,7 +35,7 @@ -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("readelf", "Displays information about ELF files", "0.2.0", +DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("GElfReaderPlugin", "readelf", "Displays information about ELF files", "0.2.0", PGA_FORMAT_PRELOAD); diff --git a/plugins/readmc/reader.c b/plugins/readmc/reader.c index e10b927..e492eeb 100644 --- a/plugins/readmc/reader.c +++ b/plugins/readmc/reader.c @@ -36,7 +36,7 @@ -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("readmc", "Displays information about Mobicore files", "0.2.0", +DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("GMCReaderPlugin", "readmc", "Displays information about Mobicore files", "0.2.0", PGA_FORMAT_PRELOAD); diff --git a/plugins/ropgadgets/plugin.c b/plugins/ropgadgets/plugin.c index 1ecb7d8..d560c88 100644 --- a/plugins/ropgadgets/plugin.c +++ b/plugins/ropgadgets/plugin.c @@ -36,7 +36,7 @@ -DEFINE_CHRYSALIDE_PLUGIN("ROP gadgets", "Find available gadgets for a ROP chain", "0.1.0", +DEFINE_CHRYSALIDE_PLUGIN("GROPPlugin", "ROP gadgets", "Find available gadgets for a ROP chain", "0.1.0", RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); diff --git a/src/core/core.c b/src/core/core.c index cdcfce5..aabff62 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -44,6 +44,7 @@ #include "../common/io.h" #include "../common/xdg.h" #include "../glibext/linesegment.h" +#include "../plugins/dt.h" @@ -87,6 +88,8 @@ bool load_all_basic_components(void) SSL_load_error_strings(); SSL_library_init(); + result &= init_chrysalide_dynamic_types(); + result &= load_main_config_parameters(); result &= ensure_user_has_rsa_keys(); @@ -142,6 +145,8 @@ void unload_all_basic_components(void) unload_main_config_parameters(); + exit_chrysalide_dynamic_types(); + ERR_free_strings(); } diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 996c418..4059e0b 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libplugins.la libplugins_la_SOURCES = \ context-int.h \ context.h context.c \ + dt.h dt.c \ pglist.h pglist.c \ plugin-def.h \ plugin-int.h \ diff --git a/src/plugins/dt.c b/src/plugins/dt.c new file mode 100644 index 0000000..afdba21 --- /dev/null +++ b/src/plugins/dt.c @@ -0,0 +1,474 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dt.c - possibilité de créer de nouveaux types de façon dynamique + * + * 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 Chrysalide. If not, see . + */ + + +#include "dt.h" + + +#include +#include + + + +/* ------------------------- MODULE DE GESTION DES NOUVEAUX ------------------------- */ + + +#define G_TYPE_DYNAMIC_TYPES g_dynamic_types_get_type() +#define G_DYNAMIC_TYPES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DYNAMIC_TYPES, GDynamicTypes)) +#define G_IS_DYNAMIC_TYPES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DYNAMIC_TYPES)) +#define G_DYNAMIC_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DYNAMIC_TYPES, GDynamicTypesClass)) +#define G_IS_DYNAMIC_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DYNAMIC_TYPES)) +#define G_DYNAMIC_TYPES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DYNAMIC_TYPES, GDynamicTypesClass)) + + +/* Mémorisation des caractéristiques de type */ +typedef struct _type_dyn_info_t +{ + GType type; /* Identifiant unique obtenu */ + GClassInitFunc init; /* Définition des méthodes */ + gconstpointer data; /* Eventuelles données utiles */ + +} type_dyn_info_t; + +/* Description de fichier binaire (instance) */ +typedef struct _GDynamicTypes +{ + GObject parent; /* A laisser en premier */ + + type_dyn_info_t **info; /* Liste d'informations utiles */ + size_t count; /* Taille de cette liste */ + +} GDynamicTypes; + +/* Description de fichier binaire (classe) */ +typedef struct _GDynamicTypesClass +{ + GObjectClass parent; /* A laisser en premier */ + +} GDynamicTypesClass; + + +/* Indique le type défini pour une gestion de types dynamique. */ +static GType g_dynamic_types_get_type(void); + +/* Initialise la classe de gestion de types dynamique. */ +static void g_dynamic_types_class_init(GDynamicTypesClass *); + +/* Initialise une gestion de types dynamique. */ +static void g_dynamic_types_init(GDynamicTypes *); + +/* Procède à l'initialisation de l'interface de typage nouveau. */ +static void g_dynamic_types_interface_init(GTypePluginClass *); + +/* Supprime toutes les références externes. */ +static void g_dynamic_types_dispose(GDynamicTypes *); + +/* Procède à la libération totale de la mémoire. */ +static void g_dynamic_types_finalize(GDynamicTypes *); + +/* Crée un nouveau gestionnaire de nouveaux types. */ +static GDynamicTypes *g_dynamic_types_new(void); + +/* Marque une augmentation des utilisations. */ +static void g_dynamic_types_use(GDynamicTypes *); + +/* Marque une diminution des utilisations. */ +static void g_dynamic_types_unuse(GDynamicTypes *); + +/* Complète la définition d'un type dynamiquement. */ +static void g_dynamic_types_complete_type(GDynamicTypes *, GType, GTypeInfo *, GTypeValueTable *); + +/* Retrouve les informations concernant un type dynamique. */ +static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *, GType); + +/* Fournit un identifiant GLib pour un nouveau type. */ +static GType g_dynamic_types_register_type(GDynamicTypes *, GType, const char *, GClassInitFunc, gconstpointer); + + + +/* ----------------------- ACCOMPAGNEMENTS DES NOUVEAUX TYPES ----------------------- */ + + +/* Encadrement des nouveaux types dérivés */ +static GDynamicTypes *_chrysalide_dtypes = NULL; + + + +/* ---------------------------------------------------------------------------------- */ +/* MODULE DE GESTION DES NOUVEAUX */ +/* ---------------------------------------------------------------------------------- */ + +/* Indique le type défini pour une gestion de types dynamique. */ +G_DEFINE_TYPE_WITH_CODE(GDynamicTypes, g_dynamic_types, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(G_TYPE_TYPE_PLUGIN, g_dynamic_types_interface_init)); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe de gestion de types dynamique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_class_init(GDynamicTypesClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_dynamic_types_dispose; + object->finalize = (GObjectFinalizeFunc)g_dynamic_types_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : types = instance à initialiser. * +* * +* Description : Initialise une gestion de types dynamique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_init(GDynamicTypes *types) +{ + +} + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* * +* Description : Procède à l'initialisation de l'interface de typage nouveau. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_interface_init(GTypePluginClass *iface) +{ + iface->use_plugin = (GTypePluginUse)g_dynamic_types_use; + iface->unuse_plugin = (GTypePluginUnuse)g_dynamic_types_unuse; + iface->complete_type_info = (GTypePluginCompleteTypeInfo)g_dynamic_types_complete_type; + +} + +/****************************************************************************** +* * +* Paramètres : types = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_dispose(GDynamicTypes *types) +{ + G_OBJECT_CLASS(g_dynamic_types_parent_class)->dispose(G_OBJECT(types)); + +} + + +/****************************************************************************** +* * +* Paramètres : types = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_finalize(GDynamicTypes *types) +{ + G_OBJECT_CLASS(g_dynamic_types_parent_class)->finalize(G_OBJECT(types)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée un nouveau gestionnaire de nouveaux types. * +* * +* Retour : Instance mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDynamicTypes *g_dynamic_types_new(void) +{ + GDynamicTypes *result; /* Adresse à retourner */ + + result = g_object_new(G_TYPE_DYNAMIC_TYPES, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : types = gestionnaire de types courant. * +* * +* Description : Marque une augmentation des utilisations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_use(GDynamicTypes *types) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : types = gestionnaire de types courant. * +* * +* Description : Marque une diminution des utilisations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_unuse(GDynamicTypes *types) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : types = gestionnaire de types courant. * +* type = nouveau type GLib à traiter. * +* info = information concernant ce type à constituer. [OUT] * +* table = table de valeur à éventuellement initialiser. [OUT] * +* * +* Description : Complète la définition d'un type dynamiquement. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_dynamic_types_complete_type(GDynamicTypes *types, GType type, GTypeInfo *info, GTypeValueTable *table) +{ + const type_dyn_info_t *nfo; /* Source d'inspiration */ + GType parent; /* Type parent du type */ + GTypeQuery query; /* Informations complémentaires*/ + + /* Consultation */ + + nfo = g_dynamic_types_find(types, type); + assert(nfo != NULL); + + parent = g_type_parent(type); + g_type_query(parent, &query); + + /* Définition */ + + info->class_size = query.class_size; + info->class_init = nfo->init; + info->class_data = nfo->data; + + info->instance_size = query.instance_size; + +} + + +/****************************************************************************** +* * +* Paramètres : parent = type GLib parent. * +* type = identifiant du type GLib à considérer. * +* * +* Description : Retrouve les informations concernant un type dynamique. * +* * +* Retour : Structure contenant les informations associées au type. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static const type_dyn_info_t *g_dynamic_types_find(const GDynamicTypes *types, GType target) +{ + type_dyn_info_t *result; /* Informations à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; + + for (i = 0; i < types->count && result == NULL; i++) + if (types->info[i]->type == target) + result = types->info[i]; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : parent = type GLib parent. * +* name = désignation du nouveau type. * +* init = procédure d'initialisation de la classe associée. * +* data = éventuelles données à associer à la future classe. * +* * +* Description : Fournit un identifiant GLib pour un nouveau type. * +* * +* Retour : identifiant d'un nouveau type valide, ou 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GType g_dynamic_types_register_type(GDynamicTypes *types, GType parent, const char *name, GClassInitFunc init, gconstpointer data) +{ + GType result; /* Identifiant à retourner */ + type_dyn_info_t *new; /* Mémorisation de paramètres */ + + /* Création d'un nouveau type adapté */ + + result = g_type_register_dynamic(parent, name, G_TYPE_PLUGIN(types), 0); + + if (result == 0) + goto exit; + + new = malloc(sizeof(type_dyn_info_t)); + + new->type = result; + new->init = init; + new->data = data; + + /* Inscription définitive */ + + types->info = realloc(types->info, ++types->count * sizeof(type_dyn_info_t *)); + + types->info[types->count - 1] = new; + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* ACCOMPAGNEMENTS DES NOUVEAUX TYPES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Lance le support de dérivations de types dans Chrysalide. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool init_chrysalide_dynamic_types(void) +{ + bool result; /* Bilan à retourner */ + + _chrysalide_dtypes = g_dynamic_types_new(); + + result = (_chrysalide_dtypes != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Arrête le support de dérivations de types dans Chrysalide. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void exit_chrysalide_dynamic_types(void) +{ + g_object_unref(G_OBJECT(_chrysalide_dtypes)); + +} + + +/****************************************************************************** +* * +* Paramètres : parent = type GLib parent. * +* name = désignation du nouveau type. * +* init = procédure d'initialisation de la classe associée. * +* data = éventuelles données à associer à la future classe. * +* * +* Description : Fournit un identifiant GLib pour un nouveau type. * +* * +* Retour : Identifiant d'un nouveau type valide, ou 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GType built_dynamic_type(GType parent, const char *name, GClassInitFunc init, gconstpointer data) +{ + GType result; /* Identifiant à retourner */ + + result = g_type_from_name(name); + + if (result == 0) + result = g_dynamic_types_register_type(_chrysalide_dtypes, parent, name, init, data); + + return result; + +} diff --git a/src/plugins/dt.h b/src/plugins/dt.h new file mode 100644 index 0000000..b9d4656 --- /dev/null +++ b/src/plugins/dt.h @@ -0,0 +1,47 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * dt.h - prototypes pour la possibilité de créer de nouveaux types de façon dynamique + * + * 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 Chrysalide. If not, see . + */ + + +#ifndef _PLUGINS_DT_H +#define _PLUGINS_DT_H + + +#include +#include + + + +/* ----------------------- ACCOMPAGNEMENTS DES NOUVEAUX TYPES ----------------------- */ + + +/* Lance le support de dérivations de types dans Chrysalide. */ +bool init_chrysalide_dynamic_types(void); + +/* Arrête le support de dérivations de types dans Chrysalide. */ +void exit_chrysalide_dynamic_types(void); + +/* Fournit un identifiant GLib pour un nouveau type. */ +GType built_dynamic_type(GType, const char *, GClassInitFunc, gconstpointer); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_DT_H */ diff --git a/src/plugins/plugin-def.h b/src/plugins/plugin-def.h index 4c59606..b8cdca8 100644 --- a/src/plugins/plugin-def.h +++ b/src/plugins/plugin-def.h @@ -45,7 +45,7 @@ typedef uint32_t plugin_abi_version_t; #define GET_ABI_MIN_VERSION(vs) ((vs >> 16) & 0xff) #define GET_ABI_REV_VERSION(vs) (vs & 0xffff) -#define CURRENT_ABI_VERSION DEFINE_PLUGIN_ABI_VERSION(0, 1, 0) +#define CURRENT_ABI_VERSION DEFINE_PLUGIN_ABI_VERSION(0, 2, 0) //#define HARD_CODE_CURRENT_ABI_VERSION const plugin_abi_version_t abi_version = CURRENT_ABI_VERSION @@ -223,6 +223,7 @@ typedef struct _plugin_interface uint64_t magic; /* Vérification a minima */ plugin_abi_version_t abi_version; /* Version du protocole utilisé*/ + const char *gtp_name; /* Désignation du GType associé*/ const char *name; /* Désignation humaine courte */ const char *desc; /* Description plus loquace */ const char *version; /* Version du greffon */ @@ -253,12 +254,13 @@ typedef struct _plugin_interface #define RL(...) BUILD_PG_LIST(.required, ((const char *[]){ __VA_ARGS__ })) -#define DEFINE_CHRYSALIDE_PLUGIN(n, d, v, r, a) \ +#define DEFINE_CHRYSALIDE_PLUGIN(t, n, d, v, r, a) \ G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = { \ \ .magic = CHRYSALIDE_PLUGIN_MAGIC, \ .abi_version = CURRENT_ABI_VERSION, \ \ + .gtp_name = t, \ .name = n, \ .desc = d, \ .version = v, \ @@ -271,12 +273,13 @@ G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = { \ \ } -#define DEFINE_CHRYSALIDE_CONTAINER_PLUGIN(n, d, v, r, a) \ +#define DEFINE_CHRYSALIDE_CONTAINER_PLUGIN(t, n, d, v, r, a) \ G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = { \ \ .magic = CHRYSALIDE_PLUGIN_MAGIC, \ .abi_version = CURRENT_ABI_VERSION, \ \ + .gtp_name = t, \ .name = n, \ .desc = d, \ .version = v, \ @@ -291,8 +294,8 @@ G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = { \ /* Interfaçage primaire avec Chrysalide */ -#define DEFINE_CHRYSALIDE_ACTIVE_PLUGIN(n, d, v, ...) \ - DEFINE_CHRYSALIDE_PLUGIN(n, d, v, EMPTY_PG_LIST(.required), AL( __VA_ARGS__ )) +#define DEFINE_CHRYSALIDE_ACTIVE_PLUGIN(t, n, d, v, ...) \ + DEFINE_CHRYSALIDE_PLUGIN(t, n, d, v, EMPTY_PG_LIST(.required), AL( __VA_ARGS__ )) diff --git a/src/plugins/plugin-int.h b/src/plugins/plugin-int.h index 2d98217..4746867 100644 --- a/src/plugins/plugin-int.h +++ b/src/plugins/plugin-int.h @@ -83,6 +83,14 @@ struct _GPluginModule bitfield_t *dependencies; /* Cartographie des dépendances*/ +}; + + +/* Greffon pour Chrysalide (classe) */ +struct _GPluginModuleClass +{ + GObjectClass parent; /* A laisser en premier */ + pg_management_fc init; /* Procédure d'initialisation */ pg_management_fc exit; /* Procédure d'extinction */ @@ -104,14 +112,6 @@ struct _GPluginModule }; -/* Greffon pour Chrysalide (classe) */ -struct _GPluginModuleClass -{ - GObjectClass parent; /* A laisser en premier */ - -}; - - /* Présente dans le journal un message simple. */ void g_plugin_module_log_simple_message(const GPluginModule *, LogMessageType, const char *); diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index a9bd9da..ff3db31 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -35,6 +35,7 @@ #include +#include "dt.h" #include "pglist.h" #include "plugin-int.h" @@ -52,6 +53,10 @@ static void g_plugin_module_dispose(GPluginModule *); /* Procède à la libération totale de la mémoire. */ static void g_plugin_module_finalize(GPluginModule *); +/* Initialise la classe des greffons d'extension. */ +static void g_plugin_module_init_gclass(GPluginModuleClass *, GModule *); + + /* Indique le type défini pour un greffon. */ G_DEFINE_TYPE(GPluginModule, g_plugin_module, G_TYPE_OBJECT); @@ -117,6 +122,7 @@ static void g_plugin_module_dispose(GPluginModule *plugin) const plugin_interface *pg_iface; /* Définition du greffon */ size_t i; /* Boucle de parcours */ GPluginModule *dependency; /* Module nécessaire */ + GPluginModuleClass *class; /* Classe de l'instance active */ pg_iface = g_plugin_module_get_interface(plugin); @@ -145,11 +151,16 @@ static void g_plugin_module_dispose(GPluginModule *plugin) } - if (plugin->exit != NULL) - plugin->exit(plugin); + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + if (class->exit != NULL) + class->exit(plugin); if (plugin->module != NULL) + { g_module_close(plugin->module); + plugin->module = NULL; + } G_OBJECT_CLASS(g_plugin_module_parent_class)->dispose(G_OBJECT(plugin)); @@ -195,25 +206,26 @@ static void g_plugin_module_finalize(GPluginModule *plugin) GPluginModule *g_plugin_module_new(const gchar *filename) { GPluginModule *result; /* Structure à retourner */ + GModule *module; /* Abstration de manipulation */ + const plugin_interface *interface; /* Déclaration d'interfaçage */ plugin_abi_version_t current; /* Version de l'ABI actuelle */ + bool valid; /* Statut de validité */ size_t i; /* Boucle de parcours */ uint32_t action; /* Identifiant d'une action */ uint32_t category; /* Catégorie principale */ uint32_t sub; /* Sous-catégorie visée */ + GType gtype; /* Nouveau type de greffon */ - result = g_object_new(G_TYPE_PLUGIN_MODULE, NULL); - - result->filename = strdup(filename); - - result->module = g_module_open(filename, G_MODULE_BIND_LAZY); - if (result->module == NULL) + module = g_module_open(filename, G_MODULE_BIND_LAZY); + if (module == NULL) { log_variadic_message(LMT_ERROR, _("Error while loading the plugin candidate '%s' : %s"), filename, g_module_error()); - goto bad_plugin; + goto bad_module; } + #define load_plugin_symbol(mod, sym, dest) \ ({ \ bool __result; \ @@ -221,7 +233,7 @@ GPluginModule *g_plugin_module_new(const gchar *filename) { \ log_variadic_message(LMT_ERROR, \ _("No '%s' entry in plugin candidate '%s'"), \ - sym, result->filename); \ + sym, filename); \ __result = false; \ } \ else __result = true; \ @@ -231,12 +243,12 @@ GPluginModule *g_plugin_module_new(const gchar *filename) /* Récupération de la version d'ABI */ - if (!load_plugin_symbol(result->module, "_chrysalide_plugin", &result->interface)) + if (!load_plugin_symbol(module, "_chrysalide_plugin", &interface)) goto bad_plugin; current = CURRENT_ABI_VERSION; - if (current != result->interface->abi_version) + if (current != interface->abi_version) { log_variadic_message(LMT_ERROR, _("ABI mismatch detected! Plugin '%s' rejected"), @@ -247,9 +259,20 @@ GPluginModule *g_plugin_module_new(const gchar *filename) /* Localisation des différents points d'entrée déclarés */ - for (i = 0; i < result->interface->actions_count; i++) + +#define check_plugin_symbol(mod, sym) \ + ({ \ + bool __result; \ + __result = g_module_symbol(mod, sym, (gpointer []) { 0 }); \ + __result; \ + }) + + + valid = true; + + for (i = 0; i < interface->actions_count && valid; i++) { - action = result->interface->actions[i]; + action = interface->actions[i]; category = MASK_PLUGIN_CATEGORY(action); sub = MASK_PLUGIN_SUB_CATEGORY(action); @@ -267,21 +290,17 @@ GPluginModule *g_plugin_module_new(const gchar *filename) switch (action) { case PGA_PLUGIN_INIT: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_init", &result->init)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_init"); break; case PGA_PLUGIN_EXIT: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_exit", &result->exit)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_exit"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - result->interface->actions[i], filename); + interface->actions[i], filename); break; } @@ -293,16 +312,13 @@ GPluginModule *g_plugin_module_new(const gchar *filename) switch (action) { case PGA_NATIVE_LOADED: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_on_native_loaded", - &result->native_loaded)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_on_native_loaded"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - result->interface->actions[i], filename); + interface->actions[i], filename); break; } @@ -327,15 +343,13 @@ GPluginModule *g_plugin_module_new(const gchar *filename) switch (action) { case PGA_GUI_THEME: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_include_theme", &result->include_theme)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_include_theme"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - result->interface->actions[i], filename); + interface->actions[i], filename); break; } @@ -361,23 +375,17 @@ GPluginModule *g_plugin_module_new(const gchar *filename) { case PGA_CONTENT_EXPLORER: case PGA_CONTENT_RESOLVER: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_handle_binary_content", - &result->handle_content)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_handle_binary_content"); break; case PGA_CONTENT_ANALYZED: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_handle_loaded_content", - &result->handle_loaded)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_handle_loaded_content"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - result->interface->actions[i], filename); + interface->actions[i], filename); break; } @@ -392,28 +400,21 @@ GPluginModule *g_plugin_module_new(const gchar *filename) case PGA_FORMAT_ANALYSIS_ENDED: case PGA_FORMAT_POST_ANALYSIS_STARTED: case PGA_FORMAT_POST_ANALYSIS_ENDED: - if (!load_plugin_symbol(result->module, - "handle_binary_format_analysis", - &result->handle_fmt_analysis)) - goto bad_plugin; + valid = check_plugin_symbol(module, "handle_binary_format_analysis"); break; case PGA_FORMAT_PRELOAD: - if (!load_plugin_symbol(result->module, - "preload_binary_format", &result->preload_format)) - goto bad_plugin; + valid = check_plugin_symbol(module, "preload_binary_format"); break; case PGA_FORMAT_ATTACH_DEBUG: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_attach_debug", &result->attach_debug)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_attach_debug"); break; default: log_variadic_message(LMT_WARNING, _("Unknown action '0x%02x' in plugin '%s'..."), - result->interface->actions[i], filename); + interface->actions[i], filename); break; } @@ -421,15 +422,11 @@ GPluginModule *g_plugin_module_new(const gchar *filename) break; case DPS_DISASSEMBLY: - if (!load_plugin_symbol(result->module, - "process_binary_disassembly", &result->process_disass)) - goto bad_plugin; + valid = check_plugin_symbol(module, "process_binary_disassembly"); break; case DPS_DETECTION: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_detect_external_tools", &result->detect)) - goto bad_plugin; + valid = check_plugin_symbol(module, "chrysalide_plugin_detect_external_tools"); break; default: @@ -450,11 +447,29 @@ GPluginModule *g_plugin_module_new(const gchar *filename) } + if (!valid) + goto bad_plugin; + + gtype = built_dynamic_type(G_TYPE_PLUGIN_MODULE, interface->gtp_name, + (GClassInitFunc)g_plugin_module_init_gclass, module); + + if (gtype == G_TYPE_INVALID) + goto bad_plugin; + + result = g_object_new(gtype, NULL); + + result->filename = strdup(filename); + result->module = module; + + result->interface = interface; + return result; bad_plugin: - g_object_unref(G_OBJECT(result)); + g_module_close(module); + + bad_module: return NULL; @@ -463,6 +478,212 @@ GPluginModule *g_plugin_module_new(const gchar *filename) /****************************************************************************** * * +* Paramètres : class = classe à initialiser. * +* module = module représentant le greffon chargé en mémoire. * +* * +* Description : Initialise la classe des greffons d'extension. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_plugin_module_init_gclass(GPluginModuleClass *class, GModule *module) +{ + const plugin_interface *interface; /* Déclaration d'interfaçage */ + size_t i; /* Boucle de parcours */ + uint32_t action; /* Identifiant d'une action */ + uint32_t category; /* Catégorie principale */ + uint32_t sub; /* Sous-catégorie visée */ + + +#undef load_plugin_symbol + +#define load_plugin_symbol(mod, sym, dest) \ + ({ \ + bool __result; \ + __result = g_module_symbol(mod, sym, (gpointer *)dest); \ + assert(__result); \ + __result; \ + }) + + + load_plugin_symbol(module, "_chrysalide_plugin", &interface); + + for (i = 0; i < interface->actions_count; i++) + { + action = interface->actions[i]; + category = MASK_PLUGIN_CATEGORY(action); + sub = MASK_PLUGIN_SUB_CATEGORY(action); + + switch (category) + { + case DPC_BASIC: + + switch (sub) + { + case DPS_NONE: + break; + + case DPS_PG_MANAGEMENT: + + switch (action) + { + case PGA_PLUGIN_INIT: + load_plugin_symbol(module, "chrysalide_plugin_init", &class->init); + break; + + case PGA_PLUGIN_EXIT: + load_plugin_symbol(module, "chrysalide_plugin_exit", &class->exit); + break; + + default: + assert(false); + break; + + } + + break; + + case DPS_CORE_MANAGEMENT: + + switch (action) + { + case PGA_NATIVE_LOADED: + load_plugin_symbol(module, "chrysalide_plugin_on_native_loaded", + &class->native_loaded); + break; + + default: + assert(false); + break; + + } + + break; + + default: + assert(false); + break; + + } + + break; + + case DPC_GUI: + + switch (sub) + { + case DPS_SETUP: + + switch (action) + { + case PGA_GUI_THEME: + load_plugin_symbol(module, "chrysalide_plugin_include_theme", + &class->include_theme); + break; + + default: + assert(false); + break; + + } + + break; + + default: + assert(false); + break; + + } + + break; + + case DPC_BINARY_PROCESSING: + + switch (sub) + { + case DPS_CONTENT: + + switch (action) + { + case PGA_CONTENT_EXPLORER: + case PGA_CONTENT_RESOLVER: + load_plugin_symbol(module, "chrysalide_plugin_handle_binary_content", + &class->handle_content); + break; + + case PGA_CONTENT_ANALYZED: + load_plugin_symbol(module, "chrysalide_plugin_handle_loaded_content", + &class->handle_loaded); + break; + + default: + assert(false); + break; + + } + + break; + + case DPS_FORMAT: + + switch (action) + { + case PGA_FORMAT_ANALYSIS_STARTED: + case PGA_FORMAT_ANALYSIS_ENDED: + case PGA_FORMAT_POST_ANALYSIS_STARTED: + case PGA_FORMAT_POST_ANALYSIS_ENDED: + load_plugin_symbol(module, "handle_binary_format_analysis", + &class->handle_fmt_analysis); + break; + + case PGA_FORMAT_PRELOAD: + load_plugin_symbol(module, "preload_binary_format", &class->preload_format); + break; + + case PGA_FORMAT_ATTACH_DEBUG: + load_plugin_symbol(module, "chrysalide_plugin_attach_debug", &class->attach_debug); + break; + + default: + assert(false); + break; + + } + + break; + + case DPS_DISASSEMBLY: + load_plugin_symbol(module, "process_binary_disassembly", &class->process_disass); + break; + + case DPS_DETECTION: + load_plugin_symbol(module, "chrysalide_plugin_detect_external_tools", &class->detect); + break; + + default: + assert(false); + break; + + } + + break; + + default: + assert(false); + break; + + } + + } + +} + + +/****************************************************************************** +* * * Paramètres : plugin = greffon à consulter. * * * * Description : Indique le fichier contenant le greffon manipulé. * @@ -654,6 +875,7 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co const plugin_interface *pg_iface; /* Définition du greffon */ size_t i; /* Boucle de parcours */ GPluginModule *dependency; /* Module nécessaire */ + GPluginModuleClass *class; /* Classe de l'instance active */ char *dir; /* Répertoire modifiable */ /* Si un essai précédent a déjà échoué ou réussi... */ @@ -689,9 +911,11 @@ bool g_plugin_module_load(GPluginModule *plugin, GPluginModule **list, size_t co if (result) { - if (plugin->init != NULL) + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + if (class->init != NULL) { - result = plugin->init(plugin); + result = class->init(plugin); if (!result) { @@ -810,7 +1034,11 @@ void g_plugin_module_log_variadic_message(const GPluginModule *plugin, LogMessag void g_plugin_module_notify_native_loaded(GPluginModule *plugin, PluginAction action, void *unused) { - plugin->native_loaded(plugin, action); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + class->native_loaded(plugin, action); } @@ -832,7 +1060,11 @@ void g_plugin_module_notify_native_loaded(GPluginModule *plugin, PluginAction ac void g_plugin_module_include_theme(const GPluginModule *plugin, PluginAction action, char ***resources, size_t *count) { - plugin->include_theme(plugin, action, resources, count); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + class->include_theme(plugin, action, resources, count); } @@ -855,7 +1087,11 @@ void g_plugin_module_include_theme(const GPluginModule *plugin, PluginAction act void g_plugin_module_handle_binary_content(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status) { - return plugin->handle_content(plugin, action, content, wid, status); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + class->handle_content(plugin, action, content, wid, status); } @@ -878,7 +1114,11 @@ void g_plugin_module_handle_binary_content(const GPluginModule *plugin, PluginAc void g_plugin_module_handle_loaded_content(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t wid, GtkStatusStack *status) { - return plugin->handle_loaded(plugin, action, content, wid, status); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + return class->handle_loaded(plugin, action, content, wid, status); } @@ -901,7 +1141,11 @@ void g_plugin_module_handle_loaded_content(const GPluginModule *plugin, PluginAc bool g_plugin_module_handle_binary_format_analysis(const GPluginModule *plugin, PluginAction action, GBinFormat *format, wgroup_id_t gid, GtkStatusStack *status) { - return plugin->handle_fmt_analysis(plugin, action, format, gid, status); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + return class->handle_fmt_analysis(plugin, action, format, gid, status); } @@ -924,7 +1168,11 @@ bool g_plugin_module_handle_binary_format_analysis(const GPluginModule *plugin, bool g_plugin_module_preload_binary_format(const GPluginModule *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status) { - return plugin->preload_format(plugin, action, format, info, status); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + return class->preload_format(plugin, action, format, info, status); } @@ -945,7 +1193,11 @@ bool g_plugin_module_preload_binary_format(const GPluginModule *plugin, PluginAc void g_plugin_module_attach_debug_format(const GPluginModule *plugin, PluginAction action, GExeFormat *format) { - plugin->attach_debug(plugin, action, format); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + class->attach_debug(plugin, action, format); } @@ -968,7 +1220,11 @@ void g_plugin_module_attach_debug_format(const GPluginModule *plugin, PluginActi void g_plugin_module_process_disassembly_event(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context) { - plugin->process_disass(plugin, action, binary, status, context); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + class->process_disass(plugin, action, binary, status, context); } @@ -992,6 +1248,10 @@ void g_plugin_module_process_disassembly_event(const GPluginModule *plugin, Plug void g_plugin_module_detect_external_tools(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count) { - plugin->detect(plugin, action, content, version, names, count); + GPluginModuleClass *class; /* Classe de l'instance active */ + + class = G_PLUGIN_MODULE_GET_CLASS(plugin); + + class->detect(plugin, action, content, version, names, count); } diff --git a/src/plugins/plugin.h b/src/plugins/plugin.h index 4b3b306..cccd39b 100644 --- a/src/plugins/plugin.h +++ b/src/plugins/plugin.h @@ -59,12 +59,12 @@ typedef enum _PluginStatusFlags #define BROKEN_PLUGIN_STATUS (PSF_UNKNOW_DEP | PSF_DEP_LOOP | PSF_FAILURE) -#define G_TYPE_PLUGIN_MODULE (g_plugin_module_get_type()) -#define G_PLUGIN_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PLUGIN_MODULE, GPluginModule)) -#define G_IS_PLUGIN_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PLUGIN_MODULE)) -#define G_PLUGIN_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PLUGIN_MODULE, GPluginModuleClass)) -#define G_IS_PLUGIN_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PLUGIN_MODULE)) -#define G_PLUGIN_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PLUGIN_MODULE, GPluginModuleClass)) +#define G_TYPE_PLUGIN_MODULE (g_plugin_module_get_type()) +#define G_PLUGIN_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PLUGIN_MODULE, GPluginModule)) +#define G_IS_PLUGIN_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PLUGIN_MODULE)) +#define G_PLUGIN_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PLUGIN_MODULE, GPluginModuleClass)) +#define G_IS_PLUGIN_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PLUGIN_MODULE)) +#define G_PLUGIN_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PLUGIN_MODULE, GPluginModuleClass)) /* Indique le type défini pour un greffon. */ diff --git a/tests/plugins/__init__.py b/tests/plugins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/plugins/plugin.py b/tests/plugins/plugin.py new file mode 100644 index 0000000..6409975 --- /dev/null +++ b/tests/plugins/plugin.py @@ -0,0 +1,223 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +from chrysacase import ChrysalideTestCase +from pychrysalide import PluginModule +import gc + + +class TestPlugin(ChrysalideTestCase): + """TestCase for GPluginModule.""" + + + def testGarbageCollecting(self): + """Ensure the garbarge collector is working for plugin modules.""" + + + class MyPG_1(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG_1, self).__init__(**interface) + + + pg = MyPG_1() + self.assertIsNotNone(pg) + + + class MyPG_2(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG_2, self).__init__(**interface) + + + pg = MyPG_2() + self.assertIsNotNone(pg) + + + class MyPG_3(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG_3, self).__init__(**interface) + + + pg = MyPG_3() + self.assertIsNotNone(pg) + + + class MyPG_4(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG_4, self).__init__(**interface) + + + pg = MyPG_4() + self.assertIsNotNone(pg) + + + class MyPG_5(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG_5, self).__init__(**interface) + + + pg = MyPG_5() + self.assertIsNotNone(pg) + + + gc.collect() + + + def testCreation(self): + """Validate PluginModule creation from Python.""" + + + class MyPG_0(PluginModule): + pass + + + # TypeError: Required argument 'name' (pos 1) not found + with self.assertRaises(TypeError): + pg = MyPG_0() + + + class MyPG_1(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG_1, self).__init__(**interface) + + + pg = MyPG_1() + self.assertIsNotNone(pg) + + + class MyPG_2(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( 'ABC', ) + } + + super(MyPG_2, self).__init__(**interface) + + + # TypeError: Invalid type for plugin action. + with self.assertRaises(TypeError): + pg = MyPG_2() + + + class MyPG_3(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( PluginModule.PGA_CONTENT_EXPLORER, ) + } + + super(MyPG_3, self).__init__(**interface) + + + # TypeError: missing features for the declared actions. + with self.assertRaises(TypeError): + pg = MyPG_3() + + + class MyPG_4(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name4', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( PluginModule.PGA_CONTENT_EXPLORER, ) + } + + super(MyPG_4, self).__init__(**interface) + + def handle_binary_content(self, action, content, wid, status): + pass + + + pg = MyPG_4() + self.assertIsNotNone(pg) + + + def testDoubleUsage(self): + """Validate PluginModule double usage in Python.""" + + + class MyPG(PluginModule): + + def __init__(self): + + interface = { + 'name' : 'some_name', + 'desc' : 'Provide some information about the useless plugin', + 'version' : '0.1', + 'actions' : ( ) + } + + super(MyPG, self).__init__(**interface) + + + pg1 = MyPG() + self.assertIsNotNone(pg1) + + pg2 = MyPG() + self.assertIsNotNone(pg2) -- cgit v0.11.2-87-g4458