diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2015-07-17 16:36:21 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2015-07-17 16:36:21 (GMT) |
commit | 24d3836fcf8d443eb654b981f65478cd9923b8f1 (patch) | |
tree | 7672a28b864127e8958c3c6cce751dcf646d2fbe /plugins/pychrysa/format/format.c | |
parent | a61f089babe336b012da31a494b0f7470b6e1a9a (diff) |
Updated the Python bindings.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@552 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'plugins/pychrysa/format/format.c')
-rw-r--r-- | plugins/pychrysa/format/format.c | 505 |
1 files changed, 434 insertions, 71 deletions
diff --git a/plugins/pychrysa/format/format.c b/plugins/pychrysa/format/format.c index 423e94e..290b189 100644 --- a/plugins/pychrysa/format/format.c +++ b/plugins/pychrysa/format/format.c @@ -31,39 +31,139 @@ #include <format/format.h> -#include "../quirks.h" +#include "../helpers.h" +#include "../arch/vmpa.h" +/* ------------------------ PARCOURS DE SYMBOLES DE BINAIRES ------------------------ */ +/* Parcours des symboles présents dans un binaire */ +typedef struct _pyBinSymbolIterator +{ + PyObject_HEAD /* A laisser en premier */ + + GBinFormat *format; /* Format binaire à consulter */ + size_t next; /* Symbole binaire à présenter */ + +} pyBinSymbolIterator; + + +/* Prend acte d'un compteur de référence à 0. */ +static void py_binary_symbol_iterator_dealloc(PyObject *); + +/* Fournit un itérateur pour symboles de format binaire. */ +static PyObject *py_binary_symbol_iterator_next(PyObject *); + +/* Initialise un objet Python de type 'BinSymbolIterator'. */ +static int py_binary_symbol_iterator_init(PyObject *, PyObject *, PyObject *); + + + +/* ---------------------------- FORMAT BINAIRE GENERIQUE ---------------------------- */ + + +/* Recherche le symbole correspondant à une étiquette. */ +static PyObject *py_binary_format_find_symbol_by_label(PyObject *, PyObject *); + +/* Recherche le symbole suivant celui lié à une adresse. */ +static PyObject *py_binary_format_find_symbol_at(PyObject *, PyObject *); + +/* Recherche le symbole suivant celui lié à une adresse. */ +static PyObject *py_binary_format_find_next_symbol_at(PyObject *, PyObject *); + +/* Recherche le symbole correspondant à une adresse. */ +static PyObject *py_binary_format_resolve_symbol(PyObject *, PyObject *); + +/* Fournit la liste de tous les symboles détectés. */ +static PyObject *py_binary_format_get_symbols(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* PARCOURS DE SYMBOLES DE BINAIRES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = instance Python à libérer de la mémoire. * +* * +* Description : Prend acte d'un compteur de référence à 0. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ -#define _(str) str +static void py_binary_symbol_iterator_dealloc(PyObject *self) +{ + pyBinSymbolIterator *iterator; /* Références pour le parcours */ + /** + * Il aurait été sans doute mieux de reposer ici sur .tp_finalize, + * mais cela semble impliquer de mettre en place tous les mécanismes de GC... + * + * cf. https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation + */ + iterator = (pyBinSymbolIterator *)self; + g_object_unref(G_OBJECT(iterator->format)); + Py_TYPE(self)->tp_free((PyObject *)self); -/* Crée un nouvel objet Python de type 'BinFormat'. */ -static PyObject *py_binary_format_new(PyTypeObject *, PyObject *, PyObject *); +} -/* Recherche une position dans une routine selon une adresse. */ -static PyObject *py_binary_format_resolve_relative_routine(PyObject *, PyObject *); +/****************************************************************************** +* * +* Paramètres : self = itérateur à manipuler. * +* * +* Description : Fournit un itérateur pour symboles de format binaire. * +* * +* Retour : Instance Python prête à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ -/* Fournit le prototype de toutes les routines détectées. */ -static PyObject *py_binary_format_get_routines(PyObject *, void *); +static PyObject *py_binary_symbol_iterator_next(PyObject *self) +{ + PyObject *result; /* Instance à retourner */ + pyBinSymbolIterator *iterator; /* Références pour le parcours */ + size_t count; /* Nombre de symboles présents */ + GBinSymbol **symbols; /* Liste de ces mêmes symboles */ + + iterator = (pyBinSymbolIterator *)self; + + symbols = g_binary_format_get_symbols(iterator->format, &count); + + if (iterator->next < count) + { + result = pygobject_new(G_OBJECT(symbols[iterator->next])); + iterator->next++; + } + else + { + PyErr_SetNone(PyExc_StopIteration); + result = NULL; + } + return result; +} /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet instancié à initialiser. * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'BinFormat'. * +* Description : Initialise un objet Python de type 'BinSymbolIterator'. * * * * Retour : Instance Python mise en place. * * * @@ -71,168 +171,431 @@ static PyObject *py_binary_format_get_routines(PyObject *, void *); * * ******************************************************************************/ -static PyObject *py_binary_format_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_binary_symbol_iterator_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + pyBinSymbolIterator *iterator; /* Références pour le parcours */ + PyObject *format; /* Format binaire en Python */ + int ret; /* Bilan de lecture des args. */ + + ret = PyArg_ParseTuple(args, "O", &format); + if (!ret) return -1; + + ret = PyObject_IsInstance(format, (PyObject *)get_python_binary_format_type()); + if (!ret) return -1; + + iterator = (pyBinSymbolIterator *)self; + + iterator->format = G_BIN_FORMAT(pygobject_get(format)); + g_object_ref(G_OBJECT(iterator->format)); + + iterator->next = 0; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_binary_symbol_iterator_type(void) { - PyErr_SetString(PyExc_ValueError, - _("pychrysalide.format.BinFormat can not be instanciated directly")); + static PyTypeObject py_binary_symbol_iterator_type = { - return NULL; + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.format.BinSymbolIterator", + .tp_basicsize = sizeof(pyBinSymbolIterator), + + .tp_dealloc = py_binary_symbol_iterator_dealloc, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = "Iterator for binary symbols", + + .tp_iter = PyObject_SelfIter, + .tp_iternext = py_binary_symbol_iterator_next, + + .tp_init = py_binary_symbol_iterator_init, + + .tp_new = PyType_GenericNew, + + }; + + return &py_binary_symbol_iterator_type; } +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide...BinSymbolIterator'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_binary_symbol_iterator(PyObject *module) +{ + PyTypeObject *py_binary_symbol_iterator_type; /* Type Python 'BinSymbolIterator' */ + int ret; /* Bilan d'un appel */ + + py_binary_symbol_iterator_type = get_python_binary_symbol_iterator_type(); + py_binary_symbol_iterator_type->tp_base = &PyBaseObject_Type; + if (PyType_Ready(py_binary_symbol_iterator_type) != 0) + return false; + Py_INCREF(py_binary_symbol_iterator_type); + ret = PyModule_AddObject(module, "BinSymbolIterator", (PyObject *)py_binary_symbol_iterator_type); + if (ret != 0) return false; + return true; +} +/* ---------------------------------------------------------------------------------- */ +/* FORMAT BINAIRE GENERIQUE */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : self = classe représentant un format binaire. * +* Paramètres : self = classe représentant un binaire. * * args = arguments fournis à l'appel. * * * -* Description : Recherche une position dans une routine selon une adresse. * +* Description : Recherche le symbole correspondant à une étiquette. * * * -* Retour : Tuple (nom, décallage) ou Py_None. * +* Retour : Symbol trouvé si l'opération a été un succès, None sinon. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_binary_format_resolve_relative_routine(PyObject *self, PyObject *args) +static PyObject *py_binary_format_find_symbol_by_label(PyObject *self, PyObject *args) { - PyObject *result; /* Tuple à retourner */ - GBinFormat *format; /* Format à manipuler */ - vmpa_t addr; /* Adresse demandée en visuel */ + PyObject *result; /* Valeur à retourner */ + PyObject *label; /* Etiquette à retrouver */ int ret; /* Bilan de lecture des args. */ - bool found; /* Bilan de la résolution */ - const char *label; /* Désignation de la trouvaille*/ + GBinFormat *format; /* Format de binaire manipulé */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + bool found; - format = G_BIN_FORMAT(pygobject_get(self)); + ret = PyArg_ParseTuple(args, "O", &label); + if (!ret) return NULL; + + ret = PyUnicode_Check(label); + if (!ret) return NULL; - ret = PyArg_ParseTuple(args, "K", &addr); - if (!ret) Py_RETURN_NONE; + format = G_BIN_FORMAT(pygobject_get(self)); - found = g_binary_format_resolve_relative_routine(format, &label, &addr); - if (!found) Py_RETURN_NONE; + found = g_binary_format_find_symbol_by_label(format, PyUnicode_DATA(label), &symbol); - result = PyTuple_New(2); - PyTuple_SetItem(result, 0, PyString_FromString(label)); - PyTuple_SetItem(result, 1, PyLong_FromLongLong(addr)); + if (found) + result = pygobject_new(G_OBJECT(symbol)); + else + { + result = Py_None; + Py_INCREF(result); + } return result; } +/****************************************************************************** +* * +* Paramètres : self = classe représentant un binaire. * +* args = arguments fournis à l'appel. * +* * +* Description : Recherche le symbole suivant celui lié à une adresse. * +* * +* Retour : Symbol trouvé si l'opération a été un succès, None sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ +static PyObject *py_binary_format_find_symbol_at(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + PyObject *py_vmpa; /* Localisation version Python */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + bool found; + + ret = PyArg_ParseTuple(args, "O", &py_vmpa); + if (!ret) return NULL; + ret = PyObject_IsInstance(py_vmpa, (PyObject *)get_python_vmpa_type()); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + found = g_binary_format_find_symbol_at(format, get_internal_vmpa(py_vmpa), &symbol); + + if (found) + result = pygobject_new(G_OBJECT(symbol)); + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} /****************************************************************************** * * -* Paramètres : self = classe représentant un format binaire. * -* closure = adresse non utilisée ici. * +* Paramètres : self = classe représentant un binaire. * +* args = arguments fournis à l'appel. * * * -* Description : Fournit le prototype de toutes les routines détectées. * +* Description : Recherche le symbole suivant celui lié à une adresse. * * * -* Retour : Liste de routine, vide ou non. * +* Retour : Symbol trouvé si l'opération a été un succès, None sinon. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_binary_format_get_routines(PyObject *self, void *closure) +static PyObject *py_binary_format_find_next_symbol_at(PyObject *self, PyObject *args) { - PyObject *result; /* Tuple à retourner */ - GBinFormat *format; /* Format à manipuler */ - GBinRoutine **routines; /* Routines binaires présentes */ - size_t count; /* Quantité de ces routines */ - size_t i; /* Boucle de parcours */ + PyObject *result; /* Valeur à retourner */ + PyObject *py_vmpa; /* Localisation version Python */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + bool found; + + ret = PyArg_ParseTuple(args, "O", &py_vmpa); + if (!ret) return NULL; + + ret = PyObject_IsInstance(py_vmpa, (PyObject *)get_python_vmpa_type()); + if (!ret) return NULL; format = G_BIN_FORMAT(pygobject_get(self)); - routines = g_binary_format_get_routines(format, &count); - result = PyTuple_New(count); + found = g_binary_format_find_next_symbol_at(format, get_internal_vmpa(py_vmpa), &symbol); - for (i = 0; i < count; i++) - PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(routines[i]))); + if (found) + result = pygobject_new(G_OBJECT(symbol)); + else + { + result = Py_None; + Py_INCREF(result); + } return result; } +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format binaire. * +* args = arguments fournis à l'appel. * +* * +* Description : Recherche le symbole correspondant à une adresse. * +* * +* Retour : Tuple (nom, décallage) ou Py_None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_resolve_symbol(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + PyObject *py_vmpa; /* Localisation version Python */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + phys_t diff; /* Décallage éventuel mesuré */ + bool found; + + ret = PyArg_ParseTuple(args, "O", &py_vmpa); + if (!ret) return NULL; + + ret = PyObject_IsInstance(py_vmpa, (PyObject *)get_python_vmpa_type()); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + found = g_binary_format_resolve_symbol(format, get_internal_vmpa(py_vmpa), &symbol, &diff); + + if (found) + { + result = PyTuple_New(2); + PyTuple_SetItem(result, 0, pygobject_new(G_OBJECT(symbol))); + PyTuple_SetItem(result, 1, PyLong_FromUnsignedLongLong(diff)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} /****************************************************************************** * * -* Paramètres : module = module dont la définition est à compléter. * +* Paramètres : self = classe représentant un format binaire. * +* closure = adresse non utilisée ici. * * * -* Description : Prend en charge l'objet 'pychrysalide.gui.panels.BinFormat'. * +* Description : Fournit la liste de tous les symboles détectés. * * * -* Retour : Bilan de l'opération. * +* Retour : Tableau créé ou NULL si aucun symbole trouvé. * * * * Remarques : - * * * ******************************************************************************/ -bool register_python_binary_format(PyObject *module) +static PyObject *py_binary_format_get_symbols(PyObject *self, void *closure) { - PyObject *parent_mod; /* Module Python-GObject */ - int ret; /* Bilan d'un appel */ + PyObject *result; /* Instance à retourner */ + PyTypeObject *iterator_type; /* Type Python de l'itérateur */ + PyObject *args_list; /* Arguments de mise en place */ - static PyMethodDef py_binary_format_methods[] = { + iterator_type = get_python_binary_symbol_iterator_type(); + + Py_INCREF(self); + + args_list = Py_BuildValue("(O)", self); + result = PyObject_CallObject((PyObject *)iterator_type, args_list); + + Py_DECREF(args_list); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_binary_format_type(void) +{ + static PyMethodDef py_bin_format_methods[] = { + { + "find_symbol_by_label", py_binary_format_find_symbol_by_label, + METH_VARARGS, + "find_symbol_by_label($self, label, /)\n--\n\nFind a symbol by its label." + }, + { + "find_symbol_at", py_binary_format_find_symbol_at, + METH_VARARGS, + "find_symbol_at($self, addr, /)\n--\n\nFind a symbol at a given address." + }, { - "resolve_relative_routine", (PyCFunction)py_binary_format_resolve_relative_routine, + "find_next_symbol_at", py_binary_format_find_next_symbol_at, METH_VARARGS, - "Search a position inside a routine by a given address." + "find_next_symbol_at($self, addr, /)\n--\n\nFind the symbol next to the one found at a given address." + }, + { + "resolve_symbol", py_binary_format_resolve_symbol, + METH_VARARGS, + "resolve_symbol($self, addr, /)\n--\n\nSearch a position inside a routine by a given address." }, { NULL } }; - static PyGetSetDef py_binary_format_getseters[] = { + static PyGetSetDef py_bin_format_getseters[] = { { - "routines", (getter)py_binary_format_get_routines, (setter)NULL, - "Provide the list of all detected routines in the binary format.", NULL + "symbols", py_binary_format_get_symbols, NULL, + "Iterable list of all symbols found in the binary format.", NULL }, { NULL } }; - static PyTypeObject py_binary_format_type = { + static PyTypeObject py_bin_format_type = { - PyObject_HEAD_INIT(NULL) + PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.format.BinFormat", .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, .tp_doc = "PyChrysalide binary format", - .tp_methods = py_binary_format_methods, - .tp_getset = py_binary_format_getseters, - .tp_new = (newfunc)py_binary_format_new + .tp_methods = py_bin_format_methods, + .tp_getset = py_bin_format_getseters }; - parent_mod = PyImport_ImportModule("gobject"); - if (parent_mod == NULL) return false; + return &py_bin_format_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.format.BinFormat'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_binary_format(PyObject *module) +{ + PyTypeObject *py_bin_format_type; /* Type Python 'BinFormat' */ + int ret; /* Bilan d'un appel */ + PyObject *dict; /* Dictionnaire du module */ - py_binary_format_type.tp_base = (PyTypeObject *)PyObject_GetAttrString(parent_mod, "GObject"); - Py_DECREF(parent_mod); + py_bin_format_type = get_python_binary_format_type(); - if (PyType_Ready(&py_binary_format_type) < 0) + py_bin_format_type->tp_base = &PyGObject_Type; + py_bin_format_type->tp_basicsize = py_bin_format_type->tp_base->tp_basicsize; + + APPLY_ABSTRACT_FLAG(py_bin_format_type); + + if (PyType_Ready(py_bin_format_type) != 0) return false; - Py_INCREF(&py_binary_format_type); - ret = PyModule_AddObject(module, "BinFormat", (PyObject *)&py_binary_format_type); + Py_INCREF(py_bin_format_type); + ret = PyModule_AddObject(module, "BinFormat", (PyObject *)py_bin_format_type); + if (ret != 0) return false; + + dict = PyModule_GetDict(module); + pygobject_register_class(dict, "BinFormat", G_TYPE_BIN_FORMAT, py_bin_format_type, + Py_BuildValue("(O)", py_bin_format_type->tp_base)); - return (ret == 0); + return true; } |