diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2015-08-27 00:26:20 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2015-08-27 00:26:20 (GMT) |
commit | e07a541d1dea13a19a587f2b97d12ed3443f235b (patch) | |
tree | 95ef0ba21345c34c7c246ff824ba70317b810717 /plugins/pychrysa | |
parent | 50a657889a32a6df365bf9880a6f56bf3a0e828c (diff) |
Redefined and improved the load process for Python plugins.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@572 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'plugins/pychrysa')
-rw-r--r-- | plugins/pychrysa/Makefile.am | 4 | ||||
-rw-r--r-- | plugins/pychrysa/gui/panels/panel.c | 64 | ||||
-rw-r--r-- | plugins/pychrysa/helpers.c | 30 | ||||
-rw-r--r-- | plugins/pychrysa/helpers.h | 3 | ||||
-rw-r--r-- | plugins/pychrysa/plugin.c | 690 | ||||
-rw-r--r-- | plugins/pychrysa/plugin.h | 33 | ||||
-rw-r--r-- | plugins/pychrysa/pychrysa.c | 171 | ||||
-rw-r--r-- | plugins/pychrysa/pychrysa.h | 7 | ||||
-rw-r--r-- | plugins/pychrysa/quirks.c | 12 | ||||
-rw-r--r-- | plugins/pychrysa/quirks.h | 7 |
10 files changed, 640 insertions, 381 deletions
diff --git a/plugins/pychrysa/Makefile.am b/plugins/pychrysa/Makefile.am index e4b9739..59e876d 100644 --- a/plugins/pychrysa/Makefile.am +++ b/plugins/pychrysa/Makefile.am @@ -25,7 +25,9 @@ pychrysa_la_LDFLAGS = -module -avoid-version $(LIBGTK_LIBS) $(LIBXML_LIBS) $(LIB pychrysalide_la_SOURCES = \ helpers.h helpers.c \ - pychrysa.h pychrysa.c + plugin.h plugin.c \ + pychrysa.h pychrysa.c \ + quirks.h quirks.c pychrysalide_la_LIBADD = \ analysis/libpychrysaanalysis.la \ diff --git a/plugins/pychrysa/gui/panels/panel.c b/plugins/pychrysa/gui/panels/panel.c index e713cc0..3170a66 100644 --- a/plugins/pychrysa/gui/panels/panel.c +++ b/plugins/pychrysa/gui/panels/panel.c @@ -32,91 +32,56 @@ #include "../editem.h" +#include "../../quirks.h" -/* Crée un nouvel objet Python de type 'PanelItem'. */ -#if 0 -static PyObject *py_panel_item_new(PyTypeObject *, PyObject *, PyObject *); -#endif +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds); /* Place un panneau dans l'ensemble affiché. */ static PyObject *py_panel_item_dock(PyObject *, PyObject *); -#if 0 /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'PanelItem'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ const char *name; /* Désignation humaine */ const char *lname; /* Nom version longue */ PyGObject *widget; /* Composant visuel du panneau */ const char *path; /* Placement à l'affichage */ int ret; /* Bilan de lecture des args. */ - GEditorItem *item; /* Version GLib du format */ + GEditorItem *item; /* Elément de l'éditeur */ ret = PyArg_ParseTuple(args, "ssOs", &name, &lname, &widget, &path); - if (!ret) Py_RETURN_NONE; + if (!ret) return -1; item = g_panel_item_new(get_internal_ref(), name, lname, GTK_WIDGET(pygobject_get(widget)), path); - result = _py_panel_item_from_c(G_PANEL_ITEM(item), type); - g_object_unref(item); + /* Enregistrement auprès de PyGObject */ - return result; + ((PyGObject *)self)->obj = G_OBJECT(item); -} - - - -/****************************************************************************** -* * -* Paramètres : item = instance existante GLib. * -* type = éventuel type final de l'instance Python imposé. * -* * -* Description : Crée un nouvel objet Python de type 'PanelItem'. * -* * -* Retour : Instance Python mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyObject *_py_panel_item_from_c(GPanelItem *item, PyTypeObject *type) -{ - PyObject *module; /* Module d'appartenance */ - - if (type == NULL) - { - module = PyImport_ImportModule("pychrysalide.gui.panels"); - type = (PyTypeObject *)PyObject_GetAttrString(module, "PanelItem"); - Py_DECREF(module); - /* FIXME : type refcount ? */ - } - else Py_INCREF(type); - - pychrysalide_set_instance_data(G_OBJECT(item), type); + pygobject_register_wrapper(self); - return pygobject_new(G_OBJECT(item)); + return 0; } -#endif /****************************************************************************** @@ -185,8 +150,7 @@ PyTypeObject *get_python_panel_item_type(void) .tp_methods = py_panel_item_methods, .tp_getset = py_panel_item_getseters, - //.tp_new = (newfunc)py_panel_item_new, - //.tp_init = (initproc)pychrysalide_allow_args_for_gobjects + .tp_init = (initproc)py_panel_item_init }; diff --git a/plugins/pychrysa/helpers.c b/plugins/pychrysa/helpers.c index d344a7f..5ba2fb4 100644 --- a/plugins/pychrysa/helpers.c +++ b/plugins/pychrysa/helpers.c @@ -27,6 +27,36 @@ /****************************************************************************** * * +* Paramètres : target = propriétaire de la routine visée. * +* method = désignation de la fonction à appeler. * +* * +* Description : Indique si une routine Python existe ou non. * +* * +* Retour : Bilan de l'analyse. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool has_python_method(PyObject *module, const char *method) +{ + bool result; /* Bilan à retourner */ + PyObject *func; /* Fonction visée */ + + func = PyObject_GetAttrString(module, method); + if (func == NULL) return false; + + result = PyCallable_Check(func); + + Py_DECREF(func); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : func = fonction Python à appeler. * * args = arguments à associer à l'opération. * * * diff --git a/plugins/pychrysa/helpers.h b/plugins/pychrysa/helpers.h index d47d8e7..bd11459 100644 --- a/plugins/pychrysa/helpers.h +++ b/plugins/pychrysa/helpers.h @@ -30,6 +30,9 @@ +/* Indique si une routine Python existe ou non. */ +bool has_python_method(PyObject *, const char *); + /* Appelle une routine Python. */ PyObject *_run_python_method(PyObject *, PyObject *); diff --git a/plugins/pychrysa/plugin.c b/plugins/pychrysa/plugin.c index e1db3de..44cb0d8 100644 --- a/plugins/pychrysa/plugin.c +++ b/plugins/pychrysa/plugin.c @@ -26,20 +26,14 @@ #include <pygobject.h> +#include <string.h> #include <common/extstr.h> - -#include "../../src/analysis/binary.h" -#include "../../src/plugins/plugin-int.h" +#include <plugins/plugin-int.h> #include "helpers.h" -#include "analysis/binary.h" -//#include "debug/debugger.h" - - - @@ -71,9 +65,20 @@ static void g_python_plugin_class_init(GPythonPluginClass *); /* Initialise l'instance d'un greffon Python. */ static void g_python_plugin_init(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 *, GObject *); +/* Procède à l'extinction du greffon. */ +static bool g_python_plugin_do_exit(GPythonPlugin *, GObject *); + + + + + + /* Indique l'utilité pratique du greffon. */ static PluginAction g_python_plugin_get_action(const GPythonPlugin *); @@ -92,49 +97,8 @@ static bool g_python_plugin_execute_on_binary(GPythonPlugin *, GLoadedBinary *, /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ -/* Classe plugin pour Python */ -typedef struct _pychrysa_plugin -{ - PyObject_HEAD - -} pychrysa_plugin; - - - - - - -/* Crée un nouveau greffon Python abstrait. */ -static PyObject *pychrysa_plugin_new(PyTypeObject *, PyObject *, PyObject *); - -/* Exécute une action valide pour le greffon Python. */ -static PyObject *pychrysa_plugin_run(PyObject *, PyObject *); - - - /* Définit les constantes pour les greffons en Python. */ -static bool pychrysa_plugin_define_constants(PyObject *); - -/* Procède à l'initialisation du greffon. */ -static PyObject *pychrysa_plugin_init(PyObject *, PyObject *); - -/* Définit le comportement par défaut d'un greffon Python. */ -static PyObject *pychrysa_plugin_get_action(PyObject *, PyObject *); - -/* Définit l'issue de la recherche d'un format par défaut. */ -static PyObject *pychrysa_plugin_is_matching(PyObject *, PyObject *); - - -/* Exécute une action relative à un débogueur. */ -//static PyObject *pychrysa_plugin_handle_debugger(PyObject *, PyObject *); - - - - - - - - +static bool py_plugin_module_define_constants(PyTypeObject *); @@ -196,6 +160,7 @@ static void g_python_plugin_init(GPythonPlugin *plugin) * * * Paramètres : modname = nom du module à charger. * * filename = chemin d'accès au code Python à charger. * +* ref = espace de référencement global. * * * * Description : Crée un greffon à partir de code Python. * * * @@ -205,33 +170,62 @@ static void g_python_plugin_init(GPythonPlugin *plugin) * * ******************************************************************************/ -GPluginModule *g_python_plugin_new(const char *modname, const char *filename) +GPluginModule *g_python_plugin_new(const char *modname, const char *filename, GObject *ref) { 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 category; /* Catégorie principale */ + uint32_t sub; /* Sous-catégorie visée */ -#if PY_VERSION_HEX >= 0x03000000 - name = PyUnicode_FromString(filename); -#else - name = PyString_FromString(filename); -#endif + name = PyUnicode_FromString(modname); if (name == NULL) goto gppn_bad_exit; module = PyImport_Import(name); Py_DECREF(name); - if (module == NULL) + if (PyErr_Occurred()) { - PyErr_Print(); - goto gppn_bad_exit; + 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, modname); + class = PyDict_GetItemString(dict, "AutoLoad"); if (class == NULL) goto gppn_no_class; if (!PyType_Check(class->ob_type)) goto gppn_no_class; @@ -241,28 +235,154 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) result = g_object_new(G_TYPE_PYTHON_PLUGIN, NULL); - //G_PLUGIN_MODULE(result)->name = strdup(modname); - //G_PLUGIN_MODULE(result)->name = stradd(G_PLUGIN_MODULE(result)->name, ".py"); - //G_PLUGIN_MODULE(result)->filename = strdup(G_PLUGIN_MODULE(result)->name); + G_PLUGIN_MODULE(result)->filename = strdup(filename); + + result->module = module; + result->instance = instance; + + if (!g_python_plugin_read_interface(result)) + { + printf("bad interface------------\n"); + goto gppn_interface_error; + } + - G_PLUGIN_MODULE(result)->init = (init_plugin_fc)g_python_plugin_do_init; - G_PLUGIN_MODULE(result)->get_action = (get_plugin_action_fc)g_python_plugin_get_action; + //G_PLUGIN_MODULE(result)->get_action = (get_plugin_action_fc)g_python_plugin_get_action; //G_PLUGIN_MODULE(result)->is_matching = (is_matching_fc)g_python_plugin_is_matching; - result->module = module; - result->instance = instance; + + + + + + + /* Localisation des différents points d'entrée déclarés */ + +#define register_python_binding(inst, sym, binding) \ + ({ \ + bool __result; \ + if (!has_python_method(inst, #sym)) \ + { \ + log_variadic_message(LMT_ERROR, \ + _("No '%s' entry in plugin candidate '%s'"), \ + #sym, 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++) + { + category = MASK_PLUGIN_CATEGORY(G_PLUGIN_MODULE(result)->interface->actions[i]); + sub = MASK_PLUGIN_SUB_CATEGORY(G_PLUGIN_MODULE(result)->interface->actions[i]); + + switch (category) + { + case DPC_BASIC: + + switch (sub) + { + case DPS_NONE: + break; + + case PGA_PLUGIN_INIT: + if (!register_python_binding(instance, init, (pg_management_fc)g_python_plugin_do_init)) + goto gppn_bad_plugin; + break; + + case PGA_PLUGIN_EXIT: + if (!register_python_binding(instance, exit, (pg_management_fc)g_python_plugin_do_exit)) + goto gppn_bad_plugin; + break; + + default: + log_variadic_message(LMT_WARNING, + _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); + break; + + } + + break; +#if 0 + case DPC_BINARY_PROCESSING: + + switch (sub) + { + case DPS_FORMAT: + + switch (result->interface->actions[i]) + { + + case PGA_FORMAT_LOADER_LAST: + if (!load_plugin_symbol(result->module, + "handle_binary_format", &result->handle_format)) + goto bad_plugin; + break; + + default: + log_variadic_message(LMT_WARNING, + _("Unknown action '0x%02x' in plugin '%s'..."), + result->interface->actions[i], filename); + break; + + } + + break; + + case DPS_DISASSEMBLY: + if (!load_plugin_symbol(result->module, + "process_binary_disassembly", &result->proc_disass)) + goto bad_plugin; + break; + + default: + log_variadic_message(LMT_WARNING, + _("Unknown sub-category '0x%02x' in plugin '%s'..."), sub, filename); + break; + + } + + break; +#endif + default: + log_variadic_message(LMT_WARNING, + _("Unknown category '0x%02x' in plugin '%s'..."), category, filename); + break; + + } + + } + + /* Conclusion */ + + if (!g_plugin_module_load(G_PLUGIN_MODULE(result), ref)) + goto gppn_bad_plugin; return G_PLUGIN_MODULE(result); + gppn_bad_plugin: + + gppn_interface_error: + + g_object_unref(G_OBJECT(result)); + + //Py_DECREF(instance); + gppn_no_instance: gppn_no_class: - Py_DECREF(module); + //Py_DECREF(module); gppn_bad_exit: + printf("bad exit :(\n"); return NULL; } @@ -271,6 +391,105 @@ GPluginModule *g_python_plugin_new(const char *modname, const char *filename) /****************************************************************************** * * * Paramètres : plugin = greffon à initialiser. * +* * +* Description : Reconstruit la déclaration d'interface à partir de lectures. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_python_plugin_read_interface(GPythonPlugin *plugin) +{ + 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_AsLong(action); + + } + + pgpri_failed: + + if (result) + { + final = (plugin_interface *)calloc(1, sizeof(plugin_interface)); + + memcpy(final, &interface, sizeof(interface)); + + 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. * * * * Description : Procède à l'initialisation du greffon. * @@ -286,17 +505,47 @@ static bool g_python_plugin_do_init(GPythonPlugin *plugin, GObject *ref) bool result; /* Bilan à retourner */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeur obtenue */ - int cmp; /* Bilan de la comparaison */ args = PyTuple_New(1); PyTuple_SetItem(args, 0, pygobject_new(ref)); value = run_python_method(plugin->instance, "init", args); - if (PyObject_Cmp(value, Py_True, &cmp) == -1) - result = false; - else - result = (cmp == 0); + result = PyObject_IsTrue(value); + + Py_XDECREF(value); + Py_DECREF(args); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à initialiser. * +* ref = espace de référencement global. * +* * +* Description : Procède à l'extinction du greffon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_python_plugin_do_exit(GPythonPlugin *plugin, GObject *ref) +{ + bool result; /* Bilan à retourner */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *value; /* Valeur obtenue */ + + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(ref)); + + value = run_python_method(plugin->instance, "exit", args); + + result = PyObject_IsTrue(value); Py_XDECREF(value); Py_DECREF(args); @@ -306,6 +555,12 @@ static bool g_python_plugin_do_init(GPythonPlugin *plugin, GObject *ref) } + + + + + + /****************************************************************************** * * * Paramètres : plugin = greffon de prise en charge à utiliser. * @@ -355,6 +610,9 @@ static PluginAction g_python_plugin_get_action(const GPythonPlugin *plugin) static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *plugin, char **filename, bin_t **data, off_t *length) { + return MFA_NONE; + +#if 0 MatchingFormatAction result; /* Valeur à retourner */ PyObject *args; /* Arguments pour l'appel */ PyObject *value; /* Valeurs obtenues */ @@ -439,7 +697,7 @@ static MatchingFormatAction g_python_plugin_is_matching(const GPythonPlugin *plu Py_DECREF(args); return result; - +#endif } @@ -467,7 +725,7 @@ static bool g_python_plugin_execute_on_binary(GPythonPlugin *plugin, GLoadedBina args = PyTuple_New(2); PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(binary))); - PyTuple_SetItem(args, 1, PyInt_FromLong(action)); + PyTuple_SetItem(args, 1, Py_None);//PyInt_FromLong(action)); value = run_python_method(plugin->instance, "execute_on_binary", args); @@ -508,7 +766,7 @@ static bool g_python_plugin_handle_debugger(const GPythonPlugin *plugin, GBinary args = PyTuple_New(2); PyTuple_SetItem(args, 0, py_binary_debugger_from_c(debugger)); - PyTuple_SetItem(args, 1, PyInt_FromLong(action)); + PyTuple_SetItem(args, 1, Py_None);//PyInt_FromLong(action)); value = run_python_method(plugin->instance, "handle_debugger", args); @@ -533,29 +791,10 @@ static bool g_python_plugin_handle_debugger(const GPythonPlugin *plugin, GBinary /* ---------------------------------------------------------------------------------- */ -/****************************************************************************** -* * -* Paramètres : type = type de l'objet à instancier. * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Crée un nouveau greffon Python abstrait. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ -static PyObject *pychrysa_plugin_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - pychrysa_plugin *result; /* Instance à retourner */ - result = (pychrysa_plugin *)type->tp_alloc(type, 0); - return (PyObject *)result; -} @@ -567,264 +806,123 @@ static PyObject *pychrysa_plugin_new(PyTypeObject *type, PyObject *args, PyObjec /****************************************************************************** * * -* Paramètres : dict = dictionnaire à compléter. * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * * * * Description : Définit les constantes pour les greffons en Python. * * * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool pychrysa_plugin_define_constants(PyObject *dict) -{ - int ret; /* Bilan d'un ajout */ - - //ret = PyDict_SetItemString(dict, "PGA_NONE", PyInt_FromLong(PGA_NONE)); - //if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_FORMAT_MATCHER", PyInt_FromLong(PGA_FORMAT_MATCHER)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_DISASSEMBLE", PyInt_FromLong(PGA_DISASSEMBLE)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_BINARY_DISASSEMBLED", PyInt_FromLong(PGA_BINARY_DISASSEMBLED)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_BINARY_LINKED", PyInt_FromLong(PGA_BINARY_LINKED)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_BINARY_BOUNDED", PyInt_FromLong(PGA_BINARY_BOUNDED)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_BINARY_GROUPED", PyInt_FromLong(PGA_BINARY_GROUPED)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_BINARY_PRINTED", PyInt_FromLong(PGA_BINARY_PRINTED)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_DISASS_PROCESS", PyInt_FromLong(PGA_DISASS_PROCESS)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_CODE_PROCESS", PyInt_FromLong(PGA_CODE_PROCESS)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_DEBUGGER_ATTACH", PyInt_FromLong(PGA_DEBUGGER_ATTACH)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "PGA_DEBUGGER_DETACH", PyInt_FromLong(PGA_DEBUGGER_DETACH)); - if (ret == -1) return false; - - /* PGA_FORMAT_MATCHER */ - - ret = PyDict_SetItemString(dict, "MFA_NONE", PyInt_FromLong(MFA_NONE)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "MFA_MATCHED", PyInt_FromLong(MFA_MATCHED)); - if (ret == -1) return false; - - ret = PyDict_SetItemString(dict, "MFA_RELOAD", PyInt_FromLong(MFA_RELOAD)); - if (ret == -1) return false; - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * -* args = arguments fournis à l'appel. * -* * -* Description : Procède à l'initialisation du greffon. * -* * -* Retour : Rien en équivalent Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *pychrysa_plugin_init(PyObject *self, PyObject *args) -{ - Py_INCREF(Py_True); - return Py_True; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * -* args = arguments fournis à l'appel. * -* * -* Description : Définit le comportement par défaut d'un greffon Python. * -* * -* Retour : Rien en équivalent Python. * +* Retour : true en cas de succès de l'opération, false sinon. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *pychrysa_plugin_get_action(PyObject *self, PyObject *args) +static bool py_plugin_module_define_constants(PyTypeObject *obj_type) { - return PyInt_FromLong(0/*PGA_NONE*/); - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * -* args = arguments fournis à l'appel. * -* * -* Description : Définit l'issue de la recherche d'un format par défaut. * -* * -* Retour : Rien en équivalent Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *pychrysa_plugin_is_matching(PyObject *self, PyObject *args) -{ - PyObject *result; /* Liste à retourner */ - - result = PyTuple_New(3); + bool result; /* Bilan à retourner */ - PyTuple_SetItem(result, 0, PyInt_FromLong(MFA_NONE)); - //Py_DECREF(Py_None); - PyTuple_SetItem(result, 1, Py_None); - //Py_DECREF(Py_None); - PyTuple_SetItem(result, 2, Py_None); + result = true; + + result &= PyDict_AddIntMacro(obj_type, PGA_BASIC_NONE); + result &= PyDict_AddIntMacro(obj_type, PGA_PLUGIN_INIT); + result &= PyDict_AddIntMacro(obj_type, PGA_PLUGIN_EXIT); + result &= PyDict_AddIntMacro(obj_type, PGA_FORMAT_MATCHER); + result &= PyDict_AddIntMacro(obj_type, PGA_FORMAT_LOADER_LAST); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_STARTED); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_RAW); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_HOOKED_LINK); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_HOOKED_POST); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_LIMITED); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_LOOPS); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_LINKED); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_GROUPED); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_RANKED); + result &= PyDict_AddIntMacro(obj_type, PGA_DISASSEMBLY_ENDED); return result; } - - /****************************************************************************** * * -* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * -* args = arguments fournis à l'appel. * +* Paramètres : - * * * -* Description : Exécute une action relative à un débogueur. * +* Description : Fournit un accès à une définition de type à diffuser. * * * -* Retour : True en équivalent Python. * +* Retour : Définition d'objet pour Python. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *pychrysa_plugin_handle_debugger(PyObject *self, PyObject *args) +PyTypeObject *get_python_plugin_module_type(void) { - Py_RETURN_TRUE; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe assurant le lien avec l'éditeur de messages. * -* args = arguments fournis à l'appel. * -* * -* Description : Exécute une action valide pour le greffon Python. * -* * -* Retour : Rien en équivalent Python. * -* * -* Remarques : - * -* * -******************************************************************************/ + static PyMethodDef py_plugin_module_methods[] = { + { NULL } + }; -static PyObject *pychrysa_plugin_run(PyObject *self, PyObject *args) -{ - Py_RETURN_NONE; + static PyGetSetDef py_plugin_module_getseters[] = { + { 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 = "Chrysalide plugin for Python.", + .tp_methods = py_plugin_module_methods, + .tp_getset = py_plugin_module_getseters + }; + return &py_plugin_module_type; +} /****************************************************************************** * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Ajoute l'objet 'plugin' au module Python. * +* Description : Prend en charge l'objet 'pychrysalide.PluginModule'. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -bool add_plugin_to_python_module(PyObject *module) +bool register_python_plugin_module(PyObject *module) { + PyTypeObject *py_plugin_module_type; /* Type Python 'PluginModule' */ int ret; /* Bilan d'un appel */ + PyObject *dict; /* Dictionnaire du module */ - static PyMethodDef pychrysa_plugin_methods[] = { - { - "init", (PyCFunction)pychrysa_plugin_init, - METH_VARARGS, - "Initialize the plugin." - }, - { - "get_action", (PyCFunction)pychrysa_plugin_get_action, - METH_NOARGS, - "Register the plugin for given actions." - }, - { - "is_matching", (PyCFunction)pychrysa_plugin_is_matching, - METH_VARARGS, - "Define if the given file can be handled." - }, - { - "handle_debugger", (PyCFunction)pychrysa_plugin_handle_debugger, - METH_VARARGS, - "Be notify about debugger attaching or detaching." - }, - { - "run", (PyCFunction)pychrysa_plugin_run, - METH_VARARGS, - "Run the plugin for a specific action." - }, - { NULL } - }; - - static PyTypeObject pychrysa_plugin_type = { + py_plugin_module_type = get_python_plugin_module_type(); - PyObject_HEAD_INIT(NULL) + py_plugin_module_type->tp_base = &PyGObject_Type; + py_plugin_module_type->tp_basicsize = py_plugin_module_type->tp_base->tp_basicsize; - .tp_name = "plugin.Plugin", - .tp_basicsize = sizeof(pychrysa_plugin), - - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - - .tp_doc = "PyChrysalide plugin objects", - - - .tp_methods = pychrysa_plugin_methods, - .tp_new = (newfunc)pychrysa_plugin_new - - }; - - if (PyType_Ready(&pychrysa_plugin_type) < 0) + if (PyType_Ready(py_plugin_module_type) != 0) return false; - if (!pychrysa_plugin_define_constants(pychrysa_plugin_type.tp_dict)) + if (!py_plugin_module_define_constants(py_plugin_module_type)) return false; - Py_INCREF(&pychrysa_plugin_type); - ret = PyModule_AddObject(module, "Plugin", (PyObject *)&pychrysa_plugin_type); + Py_INCREF(py_plugin_module_type); + ret = PyModule_AddObject(module, "PluginModule", (PyObject *)py_plugin_module_type); + if (ret != 0) return false; + + dict = PyModule_GetDict(module); + pygobject_register_class(dict, "PluginModule", G_TYPE_PLUGIN_MODULE, py_plugin_module_type, + Py_BuildValue("(O)", py_plugin_module_type->tp_base)); - return (ret == 0); + return true; } diff --git a/plugins/pychrysa/plugin.h b/plugins/pychrysa/plugin.h index c86a343..74e2e26 100644 --- a/plugins/pychrysa/plugin.h +++ b/plugins/pychrysa/plugin.h @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_PYOIDA_PLUGIN_H -#define _PLUGINS_PYOIDA_PLUGIN_H +#ifndef _PLUGINS_PYCHRYSA_PLUGIN_H +#define _PLUGINS_PYCHRYSA_PLUGIN_H #include <Python.h> @@ -31,16 +31,13 @@ #include <stdbool.h> -#include "../../src/plugins/plugin.h" +#include <plugins/plugin.h> /* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ - - - #define G_TYPE_PYTHON_PLUGIN (g_python_plugin_get_type()) #define G_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin)) #define G_IS_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN)) @@ -60,29 +57,19 @@ typedef struct _GPythonPluginClass GPythonPluginClass; GType g_python_plugin_get_type(void); /* Crée un greffon à partir de code Python. */ -GPluginModule *g_python_plugin_new(const char *, const char *); - - - - - - - - -int -main2(const char *filename, const char *method); - - - +GPluginModule *g_python_plugin_new(const char *, const char *, GObject *); /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ -/* Ajoute l'objet 'plugin' au module Python. */ -bool add_plugin_to_python_module(PyObject *); +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_plugin_module_type(void); + +/* Prend en charge l'objet 'pychrysalide.PluginModule'. */ +bool register_python_plugin_module(PyObject *); -#endif /* _PLUGINS_PYOIDA_PLUGIN_H */ +#endif /* _PLUGINS_PYCHRYSA_PLUGIN_H */ diff --git a/plugins/pychrysa/pychrysa.c b/plugins/pychrysa/pychrysa.c index b6f89a0..eafb358 100644 --- a/plugins/pychrysa/pychrysa.c +++ b/plugins/pychrysa/pychrysa.c @@ -214,7 +214,11 @@ bool init_plugin(GPluginModule *plugin, GObject *ref) -/////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////://///////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////://///////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////://///////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////://///////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////://///////////////////////// #include <stdio.h> @@ -224,18 +228,21 @@ bool init_plugin(GPluginModule *plugin, GObject *ref) #include <config.h> +#include <common/environment.h> +#include <common/extstr.h> #include <plugins/plugin-def.h> #include <plugins/plugin-int.h> +#include "plugin.h" +#include "quirks.h" #include "../../revision.h" - -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", PGA_ALL); +DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", PGA_PLUGIN_INIT); /* Fournit la version du programme global. */ @@ -247,7 +254,8 @@ static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *); /* Détermine si l'interpréteur lancé est celui pris en compte. */ static bool is_current_abi_suitable(void); - +/* Charge autant de greffons composés en Python que possible. */ +static bool load_python_plugins(GPluginModule *plugin, GObject *); @@ -428,10 +436,8 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) }; - // TODO : à bouger ! - //init_all_processors(); - //init_all_formats(); +#if 0 do { int argc = 0; @@ -448,11 +454,14 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) add_pixmap_directory(PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "pixmaps"); init_work_queue(NULL/* !! */); - +#endif //////////////////////// + + + if (!is_current_abi_suitable()) return NULL; @@ -468,17 +477,25 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) return NULL; } + /* Préparatifs préalables aux chargements */ + /** * Pour une raison non identifiée, si le module n'est pas préchargé, * le flot d'exécution plante dans la fonction insertdict() de Objects/dictobject.c:818. */ + pygobj_mod = PyImport_ImportModule("gi.repository.GObject"); if (pygobj_mod == NULL) + { + PyErr_SetString(PyExc_ImportError, "could not import gi.gobject"); return NULL; + } + + /* Mise en place des fonctionnalités offertes */ result = PyModule_Create(&py_chrysalide_module); - status = true; + status = register_python_plugin_module(result); status &= add_analysis_module_to_python_module(result); status &= add_arch_module_to_python_module(result); @@ -498,3 +515,139 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) return result; } + + +/****************************************************************************** +* * +* Paramètres : plugin = instance représentant le greffon Python d'origine. * +* ref = espace de référencement global. * +* * +* Description : Charge autant de greffons composés en Python que possible. * +* * +* Retour : true. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool load_python_plugins(GPluginModule *plugin, GObject *ref) +{ + char *paths; /* Emplacements de greffons */ + char *save; /* Sauvegarde pour ré-entrance */ + char *path; /* Chemin à fouiller */ + DIR *dir; /* Répertoire à parcourir */ + struct dirent entry; /* Elément trouvé */ + struct dirent *next; /* Prochain élément fourni */ + int ret; /* Bilan d'un appel système */ + char *modname; /* Nom du module pour Python */ + char *filename; /* Chemin d'accès reconstruit */ + GPluginModule *pyplugin; /* Lien vers un grffon Python */ + + paths = get_env_var("PYTHONPATH"); + + save = NULL; /* gcc... */ + + for (path = strtok_r(paths, ";", &save); + path != NULL; + path = strtok_r(NULL, ";", &save)) + { + dir = opendir(path); + if (dir == NULL) + { + perror("opendir"); + continue; + } + + g_plugin_module_log_variadic_message(plugin, LMT_INFO, + _("Looking for Python plugins in '%s'..."), + path); + + for (ret = readdir_r(dir, &entry, &next); + ret == 0 && next != NULL; + ret = readdir_r(dir, &entry, &next)) + { + if (entry.d_type != DT_DIR) continue; + if (entry.d_name[0] == '.') continue; + + modname = strdup(entry.d_name); + modname = stradd(modname, "."); + modname = stradd(modname, "__init__"); + + filename = strdup(path); + filename = stradd(filename, G_DIR_SEPARATOR_S); + filename = stradd(filename, entry.d_name); + + pyplugin = g_python_plugin_new(modname, filename, ref); + + if (pyplugin == NULL) + g_plugin_module_log_variadic_message(plugin, LMT_ERROR, + _("No suitable Python plugin found in '%s'"), + filename); + else + { + g_plugin_module_log_variadic_message(plugin, LMT_PROCESS, + _("Loaded the Python plugin found in the '<b>%s</b>' directory"), + filename); + add_plugin_to_main_list(pyplugin); + } + + free(filename); + free(modname); + + } + + closedir(dir); + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* ref = espace de référencement global. * +* * +* Description : Prend acte du chargement du greffon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin, GObject *ref) +{ + bool result; /* Bilan à retourner */ + DIR *dir; /* Répertoire à parcourir */ + + define_internal_ref(ref); + + /* Définition des zones d'influence */ + + dir = opendir(PLUGINS_DIR G_DIR_SEPARATOR_S "python"); + + if (dir != NULL) + { + closedir(dir); + add_to_env_var("PYTHONPATH", PLUGINS_DIR G_DIR_SEPARATOR_S "python", ";"); + } + else + add_to_env_var("PYTHONPATH", PACKAGE_SOURCE_DIR G_DIR_SEPARATOR_S "plugins" \ + G_DIR_SEPARATOR_S "python", ";"); + + /* Chargement du module pour Python */ + + PyImport_AppendInittab("pychrysalide", &PyInit_pychrysalide); + + Py_Initialize(); + + PySys_SetArgv(0, (wchar_t *[]) { NULL }); + + result = load_python_plugins(plugin, ref); + + return result; + +} diff --git a/plugins/pychrysa/pychrysa.h b/plugins/pychrysa/pychrysa.h index 0fdc074..4e36e00 100644 --- a/plugins/pychrysa/pychrysa.h +++ b/plugins/pychrysa/pychrysa.h @@ -81,9 +81,16 @@ PyMODINIT_FUNC initpychrysa(void); +#include <plugins/plugin.h> + + + /* Point d'entrée pour l'initialisation de Python. */ PyMODINIT_FUNC PyInit_pychrysalide(void); +/* Prend acte du chargement du greffon. */ +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *, GObject *); + #endif /* _PLUGINS_PYCHRYSA_H */ diff --git a/plugins/pychrysa/quirks.c b/plugins/pychrysa/quirks.c index 4aa8536..9384b37 100644 --- a/plugins/pychrysa/quirks.c +++ b/plugins/pychrysa/quirks.c @@ -26,6 +26,9 @@ + +#if 0 + //#include <pyglib.h> #include <pygobject.h> @@ -255,6 +258,15 @@ int pychrysalide_allow_args_for_gobjects(PyObject *self, PyObject *args, PyObjec return 0; } +#endif + + + + + +/* Mémorisation de l'espace de référencement global */ +static GObject *_ref = NULL; + /****************************************************************************** diff --git a/plugins/pychrysa/quirks.h b/plugins/pychrysa/quirks.h index 89977a0..f1364be 100644 --- a/plugins/pychrysa/quirks.h +++ b/plugins/pychrysa/quirks.h @@ -26,11 +26,11 @@ #define _PLUGINS_PYOIDA_QUIRKS_H -#include <Python.h> +//#include <Python.h> #include <glib-object.h> - +#if 0 /* Définit les éléments immuables pour toute association. */ void pychrysalide_init_quirks(void); @@ -45,6 +45,9 @@ PyObject *pychrysalide_get_pygobject(GObject *); /* Initialise un objet dérivé de GObject en Python. */ int pychrysalide_allow_args_for_gobjects(PyObject *, PyObject *, PyObject *); +#endif + + /* Evite à Python d'avoir à manipuler les références internes. */ GObject *_get_internal_ref(GObject *); |