summaryrefslogtreecommitdiff
path: root/plugins/pychrysalide/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/pychrysalide/plugin.c')
-rw-r--r--plugins/pychrysalide/plugin.c929
1 files changed, 543 insertions, 386 deletions
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 <common/extstr.h>
+#include <plugins/dt.h>
#include <plugins/plugin-int.h>
@@ -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,217 +455,102 @@ 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 G_PLUGIN_MODULE(result);
-
- gppn_bad_plugin:
-
- gppn_interface_error:
-
- g_object_unref(G_OBJECT(result));
-
- return NULL;
-
- gppn_no_instance:
-
- gppn_no_class:
-
- Py_DECREF(module);
-
- gppn_bad_exit:
-
- return NULL;
+ return result;
}
/******************************************************************************
* *
-* Paramètres : plugin = greffon à initialiser. *
+* Paramètres : plugin = greffon à manipuler. *
+* action = type d'action attendue. *
+* unused = variable non utilisé pour l'usage de __VA_ARGS__. *
* *
-* Description : Reconstruit la déclaration d'interface à partir de lectures. *
+* Description : Accompagne la fin du chargement des modules natifs. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_python_plugin_read_interface(GPythonPlugin *plugin)
+static void py_plugin_module_notify_native_loaded_wrapper(GPluginModule *plugin, PluginAction action)
{
- 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 */
-
- result = true;
-
- desc = run_python_method(plugin->instance, "get_interface", NULL);
- if (!PyDict_Check(desc))
- {
- result = false;
- goto pgpri_end;
- }
-
- memset(&interface, 0, sizeof(interface));
-
- /* Chargements des premières chaînes */
-
-#define READ_STR_FIELD(name) \
- str = PyDict_GetItemString(desc, #name); \
- if ((result = PyUnicode_Check(str))) \
- interface.name = strdup(PyUnicode_DATA(str)); \
-
- READ_STR_FIELD(name);
- READ_STR_FIELD(desc);
- READ_STR_FIELD(version);
-
- /* Chargement des actions supportées */
-
- tuple = PyDict_GetItemString(desc, "actions");
-
- 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;
-
- for (i = 0; i < count; i++)
- {
- action = PyList_GET_ITEM(tuple, i);
-
- interface.actions[i] = PyLong_AsUnsignedLong(action);
-
- }
-
- pgpri_failed:
-
- if (result)
- {
- final = (plugin_interface *)calloc(1, sizeof(plugin_interface));
-
- memcpy(final, &interface, sizeof(interface));
-
- final->required = (const char **)malloc(sizeof(char *));
- final->required[0] = "PyChrysalide";
- final->required_count = 1;
-
- G_PLUGIN_MODULE(plugin)->interface = final;
-
- }
- 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);
-
- if (interface.actions != NULL) free(interface.actions);
-
- }
-
- pgpri_end:
-
- Py_XDECREF(desc);
-
- return result;
}
/******************************************************************************
* *
-* Paramètres : plugin = greffon à initialiser. *
-* ref = espace de référencement global. *
+* Paramètres : plugin = greffon à manipuler. *
+* action = type d'action attendue. *
+* resources = liste de ressources à constituer. [OUT] *
+* count = taille de cette liste. [OUT] *
* *
-* Description : Procède à l'initialisation du greffon. *
+* Description : Complète une liste de resources pour thème. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_python_plugin_do_init(GPythonPlugin *plugin)
+static void py_plugin_module_include_theme_wrapper(const GPluginModule *plugin, PluginAction action, char ***resources, size_t *count)
{
- bool result; /* Bilan à retourner */
- PyThreadState *tstate; /* Contexte d'environnement */
- PyObject *value; /* Valeur obtenue */
-
- tstate = PyThreadState_Get();
-
- if (tstate != NULL)
- PyEval_RestoreThread(tstate);
-
- if (!has_python_method(plugin->instance, "init"))
- result = true;
-
- else
- {
- value = run_python_method(plugin->instance, "init", NULL);
-
- result = (value != NULL && PyObject_IsTrue(value));
-
- Py_XDECREF(value);
-
- }
-
- if (tstate != NULL)
- PyEval_SaveThread();
-
- return result;
}
/******************************************************************************
* *
-* Paramètres : plugin = greffon à initialiser. *
+* 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 à l'extinction du greffon. *
+* Description : Procède à une opération liée à un contenu binaire. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool g_python_plugin_do_exit(GPythonPlugin *plugin)
+static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *plugin, PluginAction action, GBinContent *content, wgroup_id_t wid, GtkStatusStack *status)
{
- bool result; /* Bilan à retourner */
- 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 */
- if (!has_python_method(plugin->instance, "exit"))
- result = true;
+ gstate = PyGILState_Ensure();
- else
- {
- value = run_python_method(plugin->instance, "exit", NULL);
+ pyobj = pygobject_new(G_OBJECT(plugin));
- result = (value != NULL && PyObject_IsTrue(value));
+ assert(has_python_method(pyobj, "handle_binary_content"));
- Py_XDECREF(value);
+ 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)));
- return result;
+ value = run_python_method(pyobj, "handle_binary_content", args);
+
+ Py_XDECREF(value);
+ Py_DECREF(args);
+
+ PyGILState_Release(gstate);
}
@@ -689,11 +559,11 @@ static bool g_python_plugin_do_exit(GPythonPlugin *plugin)
* *
* Paramètres : plugin = greffon à manipuler. *
* action = type d'action attendue. *
-* content = contenu binaire à traiter. *
+* content = contenu chargé à 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. *
+* Description : Procède à une opération liée à un contenu chargé. *
* *
* Retour : - *
* *
@@ -701,14 +571,19 @@ 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 py_plugin_module_handle_loaded_content_wrapper(const GPluginModule *plugin, PluginAction action, GLoadedContent *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_loaded_content"));
+
args = PyTuple_New(4);
PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
@@ -716,7 +591,7 @@ static void g_python_plugin_handle_binary_content(const GPythonPlugin *plugin, P
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);
+ value = run_python_method(pyobj, "handle_loaded_content", args);
Py_XDECREF(value);
Py_DECREF(args);
@@ -742,14 +617,19 @@ static void g_python_plugin_handle_binary_content(const GPythonPlugin *plugin, P
* *
******************************************************************************/
-static bool g_python_plugin_handle_binary_format_analysis(const GPythonPlugin *plugin, PluginAction action, GBinFormat *format, wgroup_id_t gid, GtkStatusStack *status)
+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 */
gstate = PyGILState_Ensure();
+ pyobj = pygobject_new(G_OBJECT(plugin));
+
+ assert(has_python_method(pyobj, "handle_format_analysis"));
+
args = PyTuple_New(4);
PyTuple_SetItem(args, 0, PyLong_FromUnsignedLong(action));
@@ -757,7 +637,7 @@ static bool g_python_plugin_handle_binary_format_analysis(const GPythonPlugin *p
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);
+ value = run_python_method(pyobj, "handle_format_analysis", args);
Py_XDECREF(value);
Py_DECREF(args);
@@ -785,14 +665,19 @@ static bool g_python_plugin_handle_binary_format_analysis(const GPythonPlugin *p
* *
******************************************************************************/
-static bool g_python_plugin_preload_binary_format(const GPythonPlugin *plugin, PluginAction action, GBinFormat *format, GPreloadInfo *info, GtkStatusStack *status)
+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 */
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));
@@ -800,7 +685,7 @@ static bool g_python_plugin_preload_binary_format(const GPythonPlugin *plugin, P
PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(info)));
PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(status)));
- value = run_python_method(plugin->instance, "preload_format", args);
+ value = run_python_method(pyobj, "preload_format", args);
Py_XDECREF(value);
Py_DECREF(args);
@@ -826,20 +711,25 @@ 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 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 *value; /* Valeurs obtenues */
gstate = PyGILState_Ensure();
+ pyobj = pygobject_new(G_OBJECT(plugin));
+
+ assert(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)));
- value = run_python_method(plugin->instance, "attach_debug_format", args);
+ value = run_python_method(pyobj, "attach_debug_format", args);
Py_XDECREF(value);
Py_DECREF(args);
@@ -851,9 +741,9 @@ static void g_python_plugin_attach_debug_format(const GPythonPlugin *plugin, Plu
/******************************************************************************
* *
-* Paramètres : plugin = greffon à manipuler. *
-* action = type d'action attendue. *
-* binary = binaire dont le contenu est en cours de traitement.*
+* 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. *
* *
@@ -865,14 +755,19 @@ static void g_python_plugin_attach_debug_format(const GPythonPlugin *plugin, Plu
* *
******************************************************************************/
-static void g_python_plugin_process_disass(const GPythonPlugin *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+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));
@@ -880,7 +775,7 @@ static void g_python_plugin_process_disass(const GPythonPlugin *plugin, PluginAc
PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(status)));
PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(context)));
- value = run_python_method(plugin->instance, "process_disassembly", args);
+ value = run_python_method(pyobj, "process_disassembly", args);
Py_XDECREF(value);
Py_DECREF(args);
@@ -890,6 +785,265 @@ static void g_python_plugin_process_disass(const GPythonPlugin *plugin, PluginAc
}
+/******************************************************************************
+* *
+* 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)
+{
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* 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 */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* 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)
+{
+ 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);
+
+ Py_XDECREF(plugin->instance);
+ plugin->instance = NULL;
+
+ if (tstate != NULL)
+ PyEval_SaveThread();
+
+ 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 */
+
+ Py_XDECREF(plugin->module);
+
+ final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
+
+ if (final != NULL)
+ {
+ assert(final->required_count == 1);
+ free(final->required);
+
+ free(final);
+
+ }
+
+ G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin));
+
+}
+
+
+/******************************************************************************
+* *
+* 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 *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 */
+
+ name = PyUnicode_FromString(modname);
+ if (name == NULL) goto gppn_bad_exit;
+
+ module = PyImport_Import(name);
+ Py_DECREF(name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Fetch(&err_type, &err_value, &err_traceback);
+
+ 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);
+
+ log_variadic_message(LMT_ERROR,
+ _("An error occured when importing '%s': \"%s\""), modname, err_msg);
+
+ 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;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* MODULE PYTHON POUR LES SCRIPTS */
@@ -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))