summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-08-27 00:26:20 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-08-27 00:26:20 (GMT)
commite07a541d1dea13a19a587f2b97d12ed3443f235b (patch)
tree95ef0ba21345c34c7c246ff824ba70317b810717 /plugins
parent50a657889a32a6df365bf9880a6f56bf3a0e828c (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')
-rw-r--r--plugins/pychrysa/Makefile.am4
-rw-r--r--plugins/pychrysa/gui/panels/panel.c64
-rw-r--r--plugins/pychrysa/helpers.c30
-rw-r--r--plugins/pychrysa/helpers.h3
-rw-r--r--plugins/pychrysa/plugin.c690
-rw-r--r--plugins/pychrysa/plugin.h33
-rw-r--r--plugins/pychrysa/pychrysa.c171
-rw-r--r--plugins/pychrysa/pychrysa.h7
-rw-r--r--plugins/pychrysa/quirks.c12
-rw-r--r--plugins/pychrysa/quirks.h7
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 *);