diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2021-02-07 20:30:07 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2021-02-07 20:30:07 (GMT) |
commit | 42540e681161aab0a1c27c66541ed5dc833ca411 (patch) | |
tree | a7a1329435252b7b1ac8981b6ab3a3abddcfe457 /plugins/pychrysalide/plugin.c | |
parent | 7c17177918f1bb94be7c84ca9b839155623ff05f (diff) |
Created the right place for plugins in the Python API.
Diffstat (limited to 'plugins/pychrysalide/plugin.c')
-rw-r--r-- | plugins/pychrysalide/plugin.c | 1883 |
1 files changed, 0 insertions, 1883 deletions
diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c deleted file mode 100644 index 88b20de..0000000 --- a/plugins/pychrysalide/plugin.c +++ /dev/null @@ -1,1883 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * plugin.c - interactions avec un greffon Python - * - * Copyright (C) 2018-2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "plugin.h" - - -#include <assert.h> -#include <libgen.h> -#include <malloc.h> -#include <pygobject.h> -#include <string.h> - - -#include <common/extstr.h> -#include <plugins/dt.h> -#include <plugins/pglist.h> -#include <plugins/self.h> - - -#include "access.h" -#include "constants.h" -#include "core.h" -#include "helpers.h" -#include "core/constants.h" - - - -/* ------------------------ 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); - -/* Encadre une étape de la vie d'un greffon. */ -static bool py_plugin_module_manage_wrapper(GPluginModule *); - -/* Accompagne la fin du chargement des modules natifs. */ -static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction); - -/* Complète une liste de resources pour thème. */ -static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, gboolean, char ***, size_t *); - -/* Rend compte de la création d'un panneau. */ -static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *, PluginAction, GPanelItem *); - -/* Rend compte d'un affichage ou d'un retrait de panneau. */ -static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *, PluginAction, GPanelItem *, bool); - -/* 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_known_format_analysis_wrapper(const GPluginModule *, PluginAction, GKnownFormat *, 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 --------------------- */ - - -/* Ligne de représentation de code binaire (instance) */ -struct _GPythonPlugin -{ - GPluginModule parent; /* Instance parente */ - -}; - - -/* Ligne de représentation de code binaire (classe) */ -struct _GPythonPluginClass -{ - GPluginModuleClass parent; /* Classe parente */ - -}; - - -/* Initialise la classe des greffons Python. */ -static void g_python_plugin_class_init(GPythonPluginClass *); - -/* Initialise l'instance d'un greffon Python. */ -static void g_python_plugin_init(GPythonPlugin *); - -/* Supprime toutes les références externes. */ -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 *); - -/* Fournit le nom brut associé au greffon. */ -static char *g_python_plugin_get_modname(const GPythonPlugin *); - - - -/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ - - -/* Construit le nom d'un fichier de configuration du greffon. */ -static PyObject *py_plugin_module_build_config_filename(PyObject *, PyObject *); - -/* Affiche un message dans le journal des messages système. */ -static PyObject *py_plugin_module_log_message(PyObject *, PyObject *); - -/* Fournit le nom brut associé au greffon. */ -static PyObject *py_plugin_module_get_modname(PyObject *, void *); - -/* Indique le fichier contenant le greffon manipulé. */ -static PyObject *py_plugin_module_get_filename(PyObject *, void *); - - - -/* ---------------------------------------------------------------------------------- */ -/* GLUE POUR CREATION DEPUIS PYTHON */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * -* * -* Description : Accompagne la création d'une instance dérivée en Python. * -* * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - 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 */ - - /* Validations diverses */ - - 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é */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name, - (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type, base); - - 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 : class = classe à initialiser. * -* unused = données non utilisées ici. * -* * -* Description : Initialise la classe des greffons d'extension. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unused) -{ - class->init = NULL; - class->manage = py_plugin_module_manage_wrapper; - class->exit = NULL; - - class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper; - - class->include_theme = py_plugin_module_include_theme_wrapper; - class->notify_panel = py_plugin_module_notify_panel_creation_wrapper; - class->notify_docking = py_plugin_module_notify_panel_docking_wrapper; - - class->handle_content = py_plugin_module_handle_binary_content_wrapper; - class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper; - - class->handle_fmt_analysis = py_plugin_module_handle_known_format_analysis_wrapper; - class->preload_format = py_plugin_module_preload_binary_format_wrapper; - class->attach_debug = py_plugin_module_attach_debug_format_wrapper; - - class->process_disass = py_plugin_module_process_disassembly_event_wrapper; - - class->detect = py_plugin_module_detect_external_tools_wrapper; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet à initialiser (théoriquement). * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Initialise une instance sur la base du dérivé de GObject. * -* * -* Retour : 0. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - int ret; /* Bilan d'un appel */ - GPluginModule *plugin; /* Greffon à manipuler */ - plugin_interface *iface; /* Interface à constituer */ - GPluginModule *dependency; /* Module nécessaire */ - PyObject *value; /* Valeur à présence imposée */ - size_t i; /* Boucle de parcours */ - PyObject *action; /* Identifiant d'une action */ - -#define PLUGIN_MODULE_DOC \ - "PythonModule is the class allowing the creation of Chrysalide plugins" \ - " for Python." \ - "\n" \ - "Calls to the *__init__* constructor of this abstract object expect" \ - " no particular argument.\n" \ - "\n" \ - "Several items have to be defined as class attributes in the final" \ - " class:\n" \ - "* *_name*: a string providing a small name for the plugin;\n" \ - "* *_desc*: a string for a human readable description of the plugin;\n" \ - "* *_version*: a string providing the version of the plugin;\n" \ - "* *_url*: a string for the homepage describing the plugin;\n" \ - "* *_actions*: a tuple of pychrysalide.PluginModule.PluginAction" \ - " defining the features the plugin is bringing; this list can be" \ - " empty.\n" \ - "\n" \ - "Depending on the implemented actions, some of the following methods" \ - " have to be defined for new classes:\n" \ - "* pychrysalide.PluginModule._init_config();\n" \ - "* pychrysalide.PluginModule._notify_plugins_loaded();\n" \ - "* pychrysalide.PluginModule._include_theme();\n" \ - "* pychrysalide.PluginModule._on_panel_creation;\n" \ - "* pychrysalide.PluginModule._on_panel_docking();\n" \ - "* pychrysalide.PluginModule._handle_binary_content();\n" \ - "* pychrysalide.PluginModule._handle_loaded_content();\n" \ - "* pychrysalide.PluginModule._handle_format_analysis();\n" \ - "* pychrysalide.PluginModule._preload_format();\n" \ - "* pychrysalide.PluginModule._attach_debug_format();\n" \ - "* pychrysalide.PluginModule._process_disassembly_event();\n" \ - "* pychrysalide.PluginModule._detect_external_tools()." - - /* Initialisation d'un objet GLib */ - - ret = forward_pygobjet_init(self); - if (ret == -1) return -1; - - /* Eléments de base */ - - plugin = G_PLUGIN_MODULE(pygobject_get(self)); - - iface = calloc(1, sizeof(plugin_interface)); - plugin->interface = iface; - -#define LOAD_PYTHON_IFACE(attr) \ - do \ - { \ - value = PyObject_GetAttrString(self, "_" #attr); \ - if (value == NULL) \ - { \ - PyErr_SetString(PyExc_TypeError, _("A '_" #attr "' class attributes is missing.")); \ - return -1; \ - } \ - if (PyUnicode_Check(value)) \ - { \ - iface->attr = strdup(PyUnicode_AsUTF8(value)); \ - Py_DECREF(value); \ - } \ - else \ - { \ - Py_DECREF(value); \ - PyErr_SetString(PyExc_TypeError, _("The '_" #attr "' class attributes must be a string.")); \ - return -1; \ - } \ - assert(iface->attr != NULL); \ - } \ - while (0); - - LOAD_PYTHON_IFACE(name); - LOAD_PYTHON_IFACE(desc); - LOAD_PYTHON_IFACE(version); - LOAD_PYTHON_IFACE(url); - - iface->container = false; - - /** - * Comme le greffon n'est pas passé par la résolution des dépendances, - * orchestrée par la fonction g_plugin_module_resolve_dependencies(), - * on simule l'effet attendu en obtenant une référence par un appel à - * get_plugin_by_name(). - * - * L'incrémentation des références doit coller au plus près de - * l'inscription nominative du greffon : en cas de sortie impromptue - * (lorsqu'une erreur intervient pendant un chargement par exemple), - * l'état de l'ensemble est ainsi cohérent au moment du retrait du - * greffon fautif via la fonction g_plugin_module_dispose(). - */ - - lock_plugin_list_for_reading(); - dependency = get_plugin_by_name("PyChrysalide", NULL); - unlock_plugin_list_for_reading(); - - assert(dependency != NULL); - - if (dependency == NULL) - { - PyErr_SetString(PyExc_TypeError, _("The internal name of the Python plugin has changed!")); - return -1; - } - - iface->required = malloc(sizeof(char *)); - iface->required[0] = "PyChrysalide"; - iface->required_count = 1; - - /* Validation du reste de l'interface */ - - value = PyObject_GetAttrString(self, "_actions"); - - if (value == NULL) - { - PyErr_SetString(PyExc_TypeError, _("An '_actions' class attributes is missing.")); - return -1; - } - - if (!PyTuple_Check(value)) - { - Py_DECREF(value); - PyErr_SetString(PyExc_TypeError, _("The '_actions' class attributes must be a tuple.")); - return -1; - } - - iface->actions_count = PyTuple_Size(value); - iface->actions = malloc(iface->actions_count * sizeof(plugin_action_t)); - - for (i = 0; i < iface->actions_count; i++) - { - action = PyTuple_GetItem(value, i); - - if (!PyLong_Check(action)) - { - Py_DECREF(value); - PyErr_SetString(PyExc_TypeError, _("invalid type for plugin action.")); - return -1; - } - - iface->actions[i] = PyLong_AsUnsignedLong(action); - - } - - Py_DECREF(value); - - return 0; - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* * -* Description : Encadre une étape de la vie d'un greffon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool py_plugin_module_manage_wrapper(GPluginModule *plugin) -{ - bool result; /* Bilan à faire remonter */ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_MANAGE_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _manage, "$self, action, /", \ - METH_VARARGS, \ - "Abstract method called to react to several steps of the plugin" \ - " life.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value.\n" \ - "\n" \ - "This method has to be defined in order to handle actions such as" \ - " *PLUGIN_LOADED*." \ -) - - result = true; - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_manage")) - { - args = PyTuple_New(1); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(PGA_PLUGIN_LOADED)); - - pyret = run_python_method(pyobj, "_manage", args); - - result = (pyret == Py_True); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* * -* Description : Accompagne la fin du chargement des modules natifs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin, PluginAction action) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _notify_plugins_loaded, "$self, action, /", \ - METH_VARARGS, \ - "Abstract method called once all the (native?) plugins are" \ - " loaded.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value.\n" \ - "\n" \ - "This method has to be defined in order to handle actions such as" \ - " *NATIVE_PLUGINS_LOADED* or *PLUGINS_LOADED*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_notify_plugins_loaded")) - { - args = PyTuple_New(1); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - - pyret = run_python_method(pyobj, "_notify_plugins_loaded", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* dark = indique une préférence pour la variante foncée. * -* resources = liste de ressources à constituer. [OUT] * -* count = taille de cette liste. [OUT] * -* * -* Description : Complète une liste de resources pour thème. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, gboolean dark, char ***resources, size_t *count) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *darkness; /* Valeur booléenne à joindre */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - Py_ssize_t length; /* Nombre d'éléments collectés */ - Py_ssize_t i; /* Boucle de parcours */ - PyObject *res; /* Ressource à ajouter */ - -#define PLUGIN_MODULE_INCLUDE_THEME_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _include_theme, "$self, action, dark, /", \ - METH_VARARGS, \ - "Abstract method called once all the native plugins are loaded.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the *dark* parameter indicates if a dark theme is" \ - " being to get loaded.\n" \ - "\n" \ - "The expected result is a list of CSS definition resource URIs," \ - " provided as strings such as 'resource:///org/xxx/extra.css'" \ - " for instance.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *GUI_THEME*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_include_theme")) - { - args = PyTuple_New(2); - - darkness = (dark ? Py_True : Py_False); - Py_INCREF(darkness); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, darkness); - - pyret = run_python_method(pyobj, "_include_theme", args); - - if (!PySequence_Check(pyret)) - g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list")); - - else - { - length = PySequence_Length(pyret); - - for (i = 0; i < length; i++) - { - res = PySequence_GetItem(pyret, i); - - if (!PyUnicode_Check(res)) - g_plugin_module_log_variadic_message(plugin, LMT_ERROR, - _("The returned #%zd value must be a string")); - - else - { - *resources = realloc(*resources, ++(*count) * sizeof(char **)); - *resources[*count - 1] = strdup(PyUnicode_DATA(res)); - } - - Py_DECREF(res); - - } - - } - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* item = nouveau panneau créé. * -* * -* Description : Rend compte de la création d'un panneau. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _on_panel_creation, "$self, action, item, /", \ - METH_VARARGS, \ - "Abstract method called when a new instance of panel is created.\n" \ - "\n" \ - "The expected *action* is a pychrysalide.PluginModule.PluginAction" \ - " value and the *item* is a pychrysalide.gui.PanelItem instance.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *PANEL_CREATION*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_on_panel_creation")) - { - args = PyTuple_New(2); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item))); - - pyret = run_python_method(pyobj, "_on_panel_creation", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* item = panneau marqué par un changement d'affichage. * -* dock = indique une accroche et non un décrochage. * -* * -* Description : Rend compte d'un affichage ou d'un retrait de panneau. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *plugin, PluginAction action, GPanelItem *item, bool dock) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *pydock; /* Valeur booléenne à joindre */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _on_panel_docking, "$self, action, item, dock, /", \ - METH_VARARGS, \ - "Abstract method called when a panel is docked or undocked into" \ - " the Chrysalide main graphical interface.\n" \ - "\n" \ - "The expected *action* is a pychrysalide.PluginModule.PluginAction" \ - " value, the *item* is a pychrysalide.gui.PanelItem instance and" \ - " the *dock* parameter indicates if the panel request a docking" \ - " operation or an undocking one.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *PANEL_DOCKING*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_on_panel_docking")) - { - args = PyTuple_New(3); - - pydock = (dock ? Py_True : Py_False); - Py_INCREF(pydock); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(item))); - PyTuple_SetItem(args, 2, pydock); - - pyret = run_python_method(pyobj, "_on_panel_docking", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ - -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 *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _handle_binary_content, "$self, action, content, wid, status, /", \ - METH_VARARGS, \ - "Abstract method used to explore a binary content (and possibly to add new" \ - " contents to explore) or to load a recognized binary content into a" \ - " pychrysalide.analysis.LoadedContent instance.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the initial binary content is a pychrysalide.analysis.BinContent" \ - " instance. A tracking identifier is provided and is aimed to be" \ - " used with methods from pychrysalide.analysis.ContentExplorer and" \ - " pychrysalide.analysis.ContentResolver. A reference to the main status bar" \ - " may also be provided, as a pychrysalide.gtkext.StatusStack instance if" \ - " running in graphical mode or None otherwise.\n" \ - "\n" \ - "This method has to be defined in order to handle actions such as" \ - " *CONTENT_EXPLORER* or *CONTENT_RESOLVER*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (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))); - - pyret = run_python_method(pyobj, "_handle_binary_content", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* content = contenu chargé à traiter. * -* gid = identifiant du groupe de traitement. * -* status = barre de statut à tenir informée. * -* * -* Description : Procède à une opération liée à un contenu chargé. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *content, wgroup_id_t gid, GtkStatusStack *status) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _handle_loaded_content, "$self, action, content, gid, status, /", \ - METH_VARARGS, \ - "Abstract method run once a loaded binary has been analyzed with success.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the analyzed content is a pychrysalide.analysis.LoadedContent" \ - " instance. The identifier refers to the working queue used to process the" \ - " analysis. A reference to the main status bar may also be provided, as a" \ - " pychrysalide.gtkext.StatusStack instance if running in graphical mode or" \ - " None otherwise.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *CONTENT_ANALYZED*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_handle_loaded_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(gid)); - PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status))); - - pyret = run_python_method(pyobj, "_handle_loaded_content", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ - -static bool py_plugin_module_handle_known_format_analysis_wrapper(const GPluginModule *plugin, PluginAction action, GKnownFormat *format, wgroup_id_t gid, GtkStatusStack *status) -{ - bool result; /* Bilan à retourner */ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _handle_binary_format_analysis, "$self, action, format, gid, status, /", \ - METH_VARARGS, \ - "Abstract method run at several different steps of a binary format analysis:\n" \ - "* at the beginning and at the end of the main analysis pass;\n" \ - "* at the beginning and at the end of the extra final pass.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the provided format is a pychrysalide.format.KnownFormat" \ - " instance. The identifier refers to the working queue used to process the" \ - " analysis. A reference to the main status bar may also be provided, as a" \ - " pychrysalide.gtkext.StatusStack instance if running in graphical mode or" \ - " None otherwise.\n" \ - "\n" \ - "This method has to be defined in order to handle actions such as" \ - " *FORMAT_ANALYSIS_STARTED*, *FORMAT_ANALYSIS_ENDED*," \ - " *FORMAT_POST_ANALYSIS_STARTED* or *FORMAT_POST_ANALYSIS_ENDED*." \ -) - - result = false; - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_handle_format_analysis")) - { - 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))); - - pyret = run_python_method(pyobj, "_handle_format_analysis", args); - - result = (pyret == Py_True); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return result; - -} - - -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ - -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 *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_PRELOAD_BINARY_FORMAT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _preload_binary_format, "$self, action, format, info, status, /", \ - METH_VARARGS, \ - "Abstract method which is an opportunity to setup instructions or comments" \ - " ahead of the disassembling process.\n" \ - "\n" \ - "Format fields do not need to get disassembled and may be annotated for" \ - " instance.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the provided format is a pychrysalide.format.BinFormat" \ - " instance. The information holder to fill is a pychrysalide.format.PreloadInfo"\ - " instance. A reference to the main status bar may also be provided, as a" \ - " pychrysalide.gtkext.StatusStack instance if running in graphical mode or" \ - " None otherwise.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *FORMAT_PRELOAD*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (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))); - - pyret = run_python_method(pyobj, "_preload_format", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à manipuler. * -* action = type d'action attendue. * -* format = format de binaire à manipuler pendant l'opération. * -* * -* Description : Procède au rattachement d'éventuelles infos de débogage. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_attach_debug_format_wrapper(const GPluginModule *plugin, PluginAction action, GExeFormat *format) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_ATTACH_DEBUG_FORMAT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _attach_debug_format, "$self, action, format, /", \ - METH_VARARGS, \ - "Abstract method called when a debugger is attached to a binary format.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *FORMAT_ATTACH_DEBUG*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_attach_debug_format")) - { - args = PyTuple_New(2); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(format))); - - pyret = run_python_method(pyobj, "_attach_debug_format", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* 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 *pyret; /* Bilan d'exécution */ - -#define PLUGIN_MODULE_PROCESS_DISASSEMBLY_EVENT_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _process_disassembly_event, "$self, action, format, /", \ - METH_VARARGS, \ - "Abstract method run at several different steps of a binary analysis.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the provided format is a pychrysalide.format.ExeFormat instance.\n" \ - "\n" \ - "This method has to be defined in order to handle actions such as" \ - " *DISASSEMBLY_STARTED*, *DISASSEMBLY_RAW*, *DISASSEMBLY_HOOKED_LINK*," \ - " *DISASSEMBLY_HOOKED_POST*, *DISASSEMBLY_LIMITED*, *DISASSEMBLY_LOOPS*," \ - " *DISASSEMBLY_LINKED*, *DISASSEMBLY_GROUPED*, *DISASSEMBLY_RANKED*," \ - " *DISASSEMBLY_ENDED*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_process_disassembly_event")) - { - 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))); - - pyret = run_python_method(pyobj, "_process_disassembly_event", args); - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - -/****************************************************************************** -* * -* 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 : Effectue la détection d'effets d'outils externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *plugin, PluginAction action, const GLoadedContent *content, bool version, char ***names, size_t *count) -{ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *details; /* Valeur booléenne à joindre */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *pyret; /* Bilan d'exécution */ - Py_ssize_t length; /* Nombre d'éléments collectés */ - Py_ssize_t i; /* Boucle de parcours */ - PyObject *res; /* Ressource à ajouter */ - -#define PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER PYTHON_WRAPPER_DEF \ -( \ - _detect_external_tools, "$self, action, content, version, /", \ - METH_VARARGS, \ - "Abstract method called when a detection of tools used the build" \ - " the analyzed content is required.\n" \ - "\n" \ - "The expected action is a pychrysalide.PluginModule.PluginAction" \ - " value and the content is a pychrysalide.analysis.LoadedContent" \ - " instance. The *version* parameter is a boolean value indicating" \ - " if some extra details about the tools version are wished.\n" \ - "\n" \ - "The expected result is a list of strings.\n" \ - "\n" \ - "This method has to be defined in order to handle action such as" \ - " *DETECTION_OBFUSCATORS*." \ -) - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(plugin)); - - if (has_python_method(pyobj, "_detect_external_tools")) - { - args = PyTuple_New(3); - - details = (version ? Py_True : Py_False); - Py_INCREF(details); - - PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action)); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(content))); - PyTuple_SetItem(args, 2, details); - - pyret = run_python_method(pyobj, "_detect_external_tools", args); - - if (!PySequence_Check(pyret)) - g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("The returned value must be a string list")); - - else - { - length = PySequence_Length(pyret); - - for (i = 0; i < length; i++) - { - res = PySequence_GetItem(pyret, i); - - if (!PyUnicode_Check(res)) - g_plugin_module_log_variadic_message(plugin, LMT_ERROR, - _("The returned #%zd value must be a string")); - - else - { - *names = realloc(*names, ++(*count) * sizeof(char **)); - *names[*count - 1] = strdup(PyUnicode_DATA(res)); - } - - Py_DECREF(res); - - } - - } - - Py_XDECREF(pyret); - Py_DECREF(args); - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* INTERFACE INTERNE POUR GREFFONS 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. * -* * -* Description : Initialise la classe des greffons Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_class_init(GPythonPluginClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GPluginModuleClass *plugin; /* Version parente de la classe*/ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; - object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; - - plugin = G_PLUGIN_MODULE_CLASS(klass); - - plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname; - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance à initialiser. * -* * -* Description : Initialise l'instance d'un greffon Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_init(GPythonPlugin *plugin) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_dispose(GPythonPlugin *plugin) -{ -#if 0 - PyThreadState *tstate; /* Contexte d'environnement */ - - /** - * 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. - */ - - tstate = get_pychrysalide_main_tstate(); - - if (tstate != NULL) - PyEval_RestoreThread(tstate); - - if (tstate != NULL) - PyEval_SaveThread(); -#endif - - G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_finalize(GPythonPlugin *plugin) -{ - plugin_interface *final; /* Interface finale conservée */ - - final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; - - if (final != NULL) - { - if (final->name != NULL) free(final->name); - if (final->desc != NULL) free(final->desc); - if (final->version != NULL) free(final->version); - if (final->url != NULL) free(final->url); - - assert(final->required_count == 1); - - if (final->required != NULL) - free(final->required); - - if (final->actions != NULL) - free(final->actions); - - free(final); - - } - - G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à valider. * -* * -* Description : Fournit le nom brut associé au greffon. * -* * -* Retour : Désignation brute du greffon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *g_python_plugin_get_modname(const GPythonPlugin *plugin) -{ - char *result; /* Désignation brute à renvoyer*/ - char *path; /* Chemin à traiter */ - - path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin))); - - result = strdup(basename(path)); - - free(path); - - return result; - -} - - -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ - -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 *dict; /* Dictionnaire associé */ - PyObject *class; /* Classe à instancier */ - PyObject *instance; /* Instance Python du greffon */ - - name = PyUnicode_FromString(modname); - if (name == NULL) goto bad_exit; - - module = PyImport_Import(name); - Py_DECREF(name); - - if (module == NULL) goto no_import; - - dict = PyModule_GetDict(module); - class = PyDict_GetItemString(dict, "AutoLoad"); - - if (class == NULL) goto no_class; - if (!PyType_Check(class->ob_type)) goto no_class; - - instance = PyObject_CallFunction(class, NULL); - if (instance == NULL) goto no_instance; - - result = G_PYTHON_PLUGIN(pygobject_get(instance)); - - G_PLUGIN_MODULE(result)->filename = strdup(filename); - - /** - * L'instance Python et l'objet GLib résultante sont un même PyGObject. - * - * Donc pas besoin de toucher au comptage des références ici, la libération - * se réalisera à la fin, quand l'objet GLib sera libéré. - */ - - Py_DECREF(module); - - return G_PLUGIN_MODULE(result); - - no_instance: - - log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); - - no_class: - - if (class == NULL) - log_plugin_simple_message(LMT_ERROR, - _("An error occured when looking for the 'AutoLoad': item not found!")); - - no_import: - - Py_XDECREF(module); - - log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); - - bad_exit: - - return NULL; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* MODULE PYTHON POUR LES SCRIPTS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* args = arguments fournis à l'appel. * -* * -* Description : Construit le nom d'un fichier de configuration du greffon. * -* * -* Retour : Chemin d'accès déterminé, ou NULL en cas d'erreur. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_build_config_filename(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - const char *final; /* Suffixe de fichier imposé */ - int create; /* Volonté de création */ - char *filename; /* Nom de fichier déterminé */ - -#define PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD PYTHON_METHOD_DEF \ -( \ - build_config_filename, "final, /, create=False", \ - METH_VARARGS, py_plugin_module, \ - "Build a filename suitable for the plugin configuration, ending with" \ - " the *final* suffix.\n" \ - "\n" \ - "If the *create* parameter is set, the path to this filename is" \ - " created.\n" \ - "\n" \ - "The result is a string or None on failure." \ -) - - create = 0; - - if (!PyArg_ParseTuple(args, "s|p", &final, &create)) - return NULL; - - filename = g_plugin_module_build_config_filename(G_PLUGIN_MODULE(pygobject_get(self)), final, create); - - if (filename != NULL) - { - result = PyUnicode_FromString(filename); - free(filename); - } - else - { - result = Py_None; - Py_INCREF(result); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* args = arguments fournis à l'appel. * -* * -* Description : Affiche un message dans le journal des messages système. * -* * -* Retour : Rien en équivalent Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_log_message(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - LogMessageType type; /* Espèce du message */ - const char *msg; /* Contenu du message */ - -#define PLUGIN_MODULE_LOG_MESSAGE_METHOD PYTHON_METHOD_DEF \ -( \ - log_message, "type, msg, /", \ - METH_VARARGS, py_plugin_module, \ - "Display a message in the log window, in graphical mode, or in the" \ - " console output if none.\n" \ - "\n" \ - "The type of the message has to be a pychrysalide.core.LogMessageType" \ - " value." \ - "\n" \ - "The only difference with the main pychrysalide.core.log_message()" \ - " function is that messages are automatically prefixed with the plugin" \ - " name here." \ -) - - if (!PyArg_ParseTuple(args, "O&s", convert_to_log_message_type, &type, &msg)) - return NULL; - - g_plugin_module_log_simple_message(G_PLUGIN_MODULE(pygobject_get(self)), type, msg); - - result = Py_None; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit le nom brut associé au greffon. * -* * -* Retour : Désignation brute du greffon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_get_modname(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GPluginModule *plugin; /* Version native du greffon */ - char *modname; /* Désignation brute */ - -#define PLUGIN_MODULE_MODNAME_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - modname, py_plugin_module, \ - "Raw module name of the plugin." \ -) - - plugin = G_PLUGIN_MODULE(pygobject_get(self)); - modname = g_plugin_module_get_modname(plugin); - - result = PyUnicode_FromString(modname); - - free(modname); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Indique le fichier contenant le greffon manipulé. * -* * -* Retour : Chemin d'accès au greffon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_get_filename(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GPluginModule *plugin; /* Version native du greffon */ - const char *filename; /* Chemin d'accès associé */ - -#define PLUGIN_MODULE_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - filename, py_plugin_module, \ - "Filename of the plugin." \ -) - - plugin = G_PLUGIN_MODULE(pygobject_get(self)); - filename = g_plugin_module_get_filename(plugin); - - result = PyUnicode_FromString(filename); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit la configuration mise en place pour le greffon. * -* * -* Retour : Configuration dédiée à l'extension. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_get_config(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GPluginModule *plugin; /* Version native du greffon */ - GGenConfig *config; /* Configuration associée */ - -#define PLUGIN_MODULE_CONFIG_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - config, py_plugin_module, \ - "Dedicated configuration for the plugin." \ - "\n" \ - "The value is a pychrysalide.glibext.GenConfig instance" \ - " or None if the configuration is not yet created.\n" \ - "\n" \ - "As configuration storage path depends on the plugin name," \ - " all plugin properties have to get fully loaded by the" \ - " core before the configuration can be setup." \ - "automatically" \ -) - - plugin = G_PLUGIN_MODULE(pygobject_get(self)); - config = g_plugin_module_get_config(plugin); - - if (config == NULL) - { - result = Py_None; - Py_INCREF(result); - } - - else - { - result = pygobject_new(G_OBJECT(config)); - - g_object_unref(G_OBJECT(config)); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Fournit un accès à une définition de type à diffuser. * -* * -* Retour : Définition d'objet pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyTypeObject *get_python_plugin_module_type(void) -{ - static PyMethodDef py_plugin_module_methods[] = { - PLUGIN_MODULE_MANAGE_WRAPPER, - PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER, - PLUGIN_MODULE_INCLUDE_THEME_WRAPPER, - PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER, - PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER, - PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER, - PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER, - PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER, - PLUGIN_MODULE_PRELOAD_BINARY_FORMAT_WRAPPER, - PLUGIN_MODULE_ATTACH_DEBUG_FORMAT_WRAPPER, - PLUGIN_MODULE_PROCESS_DISASSEMBLY_EVENT_WRAPPER, - PLUGIN_MODULE_DETECT_EXTERNAL_TOOLS_WRAPPER, - PLUGIN_MODULE_BUILD_CONFIG_FILENAME_METHOD, - PLUGIN_MODULE_LOG_MESSAGE_METHOD, - { NULL } - }; - - static PyGetSetDef py_plugin_module_getseters[] = { - PLUGIN_MODULE_MODNAME_ATTRIB, - PLUGIN_MODULE_FILENAME_ATTRIB, - PLUGIN_MODULE_CONFIG_ATTRIB, - { NULL } - }; - - static PyTypeObject py_plugin_module_type = { - - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "pychrysalide.PluginModule", - .tp_basicsize = sizeof(PyGObject), - - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - - .tp_doc = PLUGIN_MODULE_DOC, - - .tp_methods = py_plugin_module_methods, - .tp_getset = py_plugin_module_getseters, - - .tp_init = py_plugin_module_init, - .tp_new = py_plugin_module_new, - - }; - - return &py_plugin_module_type; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Prend en charge l'objet 'pychrysalide.PluginModule'. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool ensure_python_plugin_module_is_registered(void) -{ - PyTypeObject *type; /* Type Python 'PluginModule' */ - PyObject *module; /* Module à recompléter */ - PyObject *dict; /* Dictionnaire du module */ - - type = get_python_plugin_module_type(); - - if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) - { - module = get_access_to_python_module("pychrysalide"); - - dict = PyModule_GetDict(module); - - if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type)) - return false; - - if (!define_plugin_module_constants(type)) - return false; - - } - - return true; - -} |