From 2eca5b9056aa44760ee4981b0418652a04bfd6f2 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 12 Nov 2024 10:59:58 +0100 Subject: Prepare class renaming (GBinFormat -> GProgramFormat). --- plugins/pychrysalide/format/Makefile.am | 2 +- plugins/pychrysalide/format/format.c | 1208 ------------------- plugins/pychrysalide/format/format.h | 59 - plugins/pychrysalide/format/program.c | 1208 +++++++++++++++++++ plugins/pychrysalide/format/program.h | 59 + src/format/Makefile.am | 35 +- src/format/format-int.h | 160 --- src/format/format.c | 1920 ------------------------------- src/format/format.h | 200 ---- src/format/program-int.h | 160 +++ src/format/program.c | 1920 +++++++++++++++++++++++++++++++ src/format/program.h | 200 ++++ tests/format/format.py | 66 -- tests/format/program.py | 66 ++ 14 files changed, 3632 insertions(+), 3631 deletions(-) delete mode 100644 plugins/pychrysalide/format/format.c delete mode 100644 plugins/pychrysalide/format/format.h create mode 100644 plugins/pychrysalide/format/program.c create mode 100644 plugins/pychrysalide/format/program.h delete mode 100644 src/format/format-int.h delete mode 100644 src/format/format.c delete mode 100644 src/format/format.h create mode 100644 src/format/program-int.h create mode 100644 src/format/program.c create mode 100644 src/format/program.h delete mode 100644 tests/format/format.py create mode 100644 tests/format/program.py diff --git a/plugins/pychrysalide/format/Makefile.am b/plugins/pychrysalide/format/Makefile.am index 337265d..02f0a6e 100644 --- a/plugins/pychrysalide/format/Makefile.am +++ b/plugins/pychrysalide/format/Makefile.am @@ -5,7 +5,7 @@ libpychrysaformat_la_SOURCES = \ constants.h constants.c \ executable.h executable.c \ flat.h flat.c \ - format.h format.c \ + program.h program.c \ known.h known.c \ module.h module.c \ preload.h preload.c \ diff --git a/plugins/pychrysalide/format/format.c b/plugins/pychrysalide/format/format.c deleted file mode 100644 index 82c6c33..0000000 --- a/plugins/pychrysalide/format/format.c +++ /dev/null @@ -1,1208 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * format.c - équivalent Python du fichier "format/format.c" - * - * Copyright (C) 2018-2020 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "format.h" - - -#include - - -#include -#include -#include - - -#include "constants.h" -#include "executable.h" -#include "known.h" -#include "symbol.h" -#include "symiter.h" -#include "../access.h" -#include "../helpers.h" -#include "../analysis/constants.h" -#include "../analysis/content.h" -#include "../arch/vmpa.h" -#include "../arch/constants.h" - - - -/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ - - -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_binary_format_new(PyTypeObject *, PyObject *, PyObject *); - -/* Initialise la classe des descriptions de fichier binaire. */ -static void py_binary_format_init_gclass(GBinFormatClass *, gpointer); - -/* Initialise une instance sur la base du dérivé de GObject. */ -static int py_binary_format_init(PyObject *, PyObject *, PyObject *); - -/* Indique le boutisme employé par le format binaire analysé. */ -static SourceEndian py_binary_format_get_endianness_wrapper(const GBinFormat *); - - - -/* ---------------------------- FORMAT BINAIRE GENERIQUE ---------------------------- */ - - -/* Ajoute une information complémentaire à un format. */ -static PyObject *py_binary_format_set_flag(PyObject *, PyObject *); - -/* Retire une information complémentaire à un format. */ -static PyObject *py_binary_format_unset_flag(PyObject *, PyObject *); - -/* Détermine si un format possède un fanion particulier. */ -static PyObject *py_binary_format_has_flag(PyObject *, PyObject *); - -/* Enregistre une adresse comme début d'une zone de code. */ -static PyObject *py_binary_format_register_code_point(PyObject *, PyObject *); - -/* Ajoute un symbole à la collection du format binaire. */ -static PyObject *py_binary_format_add_symbol(PyObject *, PyObject *); - -/* Retire un symbole de la collection du format binaire. */ -static PyObject *py_binary_format_remove_symbol(PyObject *, PyObject *); - -/* 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 les particularités du format. */ -static PyObject *py_binary_format_get_flags(PyObject *, void *); - -/* Indique le boutisme employé par le format binaire analysé. */ -static PyObject *py_binary_format_get_endianness(PyObject *, void *); - -/* Fournit la liste de tous les symboles détectés. */ -static PyObject *py_binary_format_get_symbols(PyObject *, void *); - - - -/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ - - -/* Etend la liste des soucis détectés avec de nouvelles infos. */ -static PyObject *py_binary_format_add_error(PyObject *, PyObject *); - -/* Fournit les éléments concernant tous les soucis détectés. */ -static PyObject *py_binary_format_get_errors(PyObject *, void *); - - - -/* ---------------------------------------------------------------------------------- */ -/* GLUE POUR CREATION DEPUIS PYTHON */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * -* * -* Description : Accompagne la création d'une instance dérivée en Python. * -* * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Objet à retourner */ - PyTypeObject *base; /* Type de base à dériver */ - bool first_time; /* Evite les multiples passages*/ - GType gtype; /* Nouveau type de processeur */ - bool status; /* Bilan d'un enregistrement */ - - /* Validations diverses */ - - base = get_python_known_format_type(); - - if (type == base) - { - result = NULL; - PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); - goto exit; - } - - /* Mise en place d'un type dédié */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_BIN_FORMAT, type->tp_name, - (GClassInitFunc)py_binary_format_init_gclass, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type); - - if (!status) - { - result = NULL; - goto exit; - } - - } - - /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - - result = PyType_GenericNew(type, args, kwds); - - exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* unused = données non utilisées ici. * -* * -* Description : Initialise la classe générique des processeurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_binary_format_init_gclass(GBinFormatClass *class, gpointer unused) -{ - class->get_endian = py_binary_format_get_endianness_wrapper; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet à initialiser (théoriquement). * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Initialise une instance sur la base du dérivé de GObject. * -* * -* Retour : 0. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_binary_format_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - int ret; /* Bilan de lecture des args. */ - -#define BINARY_FORMAT_DOC \ - "The BinFormat class is the major poart of binary format support." \ - " It is the core class used by loading most of the binary files.\n" \ - "\n" \ - "One item has to be defined as class attribute in the final" \ - " class:\n" \ - "* *_endianness*: a pychrysalide.analysis.BinContent.SourceEndian" \ - " value indicating the endianness of the format.\n" \ - "\n" \ - "Calls to the *__init__* constructor of this abstract object expect"\ - " no particular argument." - - /* Initialisation d'un objet GLib */ - - ret = forward_pygobjet_init(self); - if (ret == -1) return -1; - - return 0; - -} - - -/****************************************************************************** -* * -* Paramètres : format = description du format connu à consulter. * -* * -* Description : Indique le boutisme employé par le format binaire analysé. * -* * -* Retour : Boutisme associé au format. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static SourceEndian py_binary_format_get_endianness_wrapper(const GBinFormat *format) -{ - SourceEndian result; /* Boutisme à retourner */ - PyGILState_STATE gstate; /* Sauvegarde d'environnement */ - PyObject *pyobj; /* Objet Python concerné */ - PyObject *pyret; /* Valeur retournée */ - int ret; /* Bilan d'une conversion */ - - result = SRE_LITTLE; - - gstate = PyGILState_Ensure(); - - pyobj = pygobject_new(G_OBJECT(format)); - - if (PyObject_HasAttrString(pyobj, "_endianness")) - { - pyret = PyObject_GetAttrString(pyobj, "_endianness"); - - if (pyret != NULL) - { - ret = convert_to_source_endian(pyret, &result); - - if (ret != 1) - result = SRE_LITTLE; - - Py_DECREF(pyret); - - } - - } - - Py_DECREF(pyobj); - - PyGILState_Release(gstate); - - return result; - -} - - -/* ---------------------------------------------------------------------------------- */ -/* FORMAT BINAIRE GENERIQUE */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : self = serveur à manipuler. * -* args = arguments d'appel non utilisés ici. * -* * -* Description : Ajoute une information complémentaire à un format. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_set_flag(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - unsigned int flag; /* Propriété à traiter */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Elément à manipuler */ - bool status; /* Bilan de l'opération */ - -#define BINARY_FORMAT_SET_FLAG_METHOD PYTHON_METHOD_DEF \ -( \ - set_flag, "$self, flag, /", \ - METH_VARARGS, py_binary_format, \ - "Add a property from a binary format.\n" \ - "\n" \ - "This property is one of the values listed in the" \ - " of pychrysalide.format.BinFormat.FormatFlag enumeration.\n" \ - "\n" \ - "If the flag was not set before the operation, True is" \ - " returned, else the result is False." \ -) - - ret = PyArg_ParseTuple(args, "I", &flag); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - status = g_binary_format_set_flag(format, flag); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = serveur à manipuler. * -* args = arguments d'appel non utilisés ici. * -* * -* Description : Retire une information complémentaire à un format. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_unset_flag(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - unsigned int flag; /* Propriété à traiter */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Elément à manipuler */ - bool status; /* Bilan de l'opération */ - -#define BINARY_FORMAT_UNSET_FLAG_METHOD PYTHON_METHOD_DEF \ -( \ - unset_flag, "$self, flag, /", \ - METH_VARARGS, py_binary_format, \ - "Remove a property from a binary format.\n" \ - "\n" \ - "This property is one of the values listed in the" \ - " of pychrysalide.format.BinFormat.FormatFlag enumeration.\n" \ - "\n" \ - "If the flag was not set before the operation, False is" \ - " returned, else the result is True." \ -) - - ret = PyArg_ParseTuple(args, "I", &flag); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - status = g_binary_format_unset_flag(format, flag); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = serveur à manipuler. * -* args = arguments d'appel non utilisés ici. * -* * -* Description : Détermine si un format possède un fanion particulier. * -* * -* Retour : Bilan de la détection. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_has_flag(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - unsigned int flag; /* Propriété à traiter */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Elément à manipuler */ - bool status; /* Bilan de l'opération */ - -#define BINARY_FORMAT_HAS_FLAG_METHOD PYTHON_METHOD_DEF \ -( \ - has_flag, "$self, flag, /", \ - METH_VARARGS, py_binary_format, \ - "Test if a binary format has a given property.\n" \ - "\n" \ - "This property is one of the values listed in the" \ - " of pychrysalide.format.BinFormat.FormatFlag enumeration.\n" \ - "\n" \ - "The result is a boolean value." \ -) - - ret = PyArg_ParseTuple(args, "I", &flag); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - status = g_binary_format_has_flag(format, flag); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe représentant un format. * -* args = arguments fournis à l'appel. * -* * -* Description : Enregistre une adresse comme début d'une zone de code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_register_code_point(PyObject *self, PyObject *args) -{ - unsigned long long pt; /* Adresse virtuelle du point */ - DisassPriorityLevel level; /* Nature du point fourni */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Format de binaire manipulé */ - -#define BINARY_FORMAT_REGISTER_CODE_POINT_METHOD PYTHON_METHOD_DEF \ -( \ - register_code_point, "$self, point, level, /", \ - METH_VARARGS, py_binary_format, \ - "Register a virtual address as entry point or basic point.\n" \ - "\n" \ - "The point is an integer value for the virtual memory location" \ - " of the new (entry) point. The type of this entry has to be a" \ - " pychrysalide.arch.ProcContext.DisassPriorityLevel value." \ -) - - ret = PyArg_ParseTuple(args, "kO&", &pt, convert_to_disass_priority_level, &level); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - g_binary_format_register_code_point(format, pt, level); - - Py_RETURN_NONE; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe représentant un format. * -* args = arguments fournis à l'appel. * -* * -* Description : Ajoute un symbole à la collection du format binaire. * -* * -* Retour : True si le symbole était bien localisé et a été inséré. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_add_symbol(PyObject *self, PyObject *args) -{ - PyObject *result; /* Valeur à retourner */ - GBinSymbol *symbol; /* Enventuel symbole trouvé */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Format de binaire manipulé */ - bool added; /* Bilan de l'appel interne */ - -#define BINARY_FORMAT_ADD_SYMBOL_METHOD PYTHON_METHOD_DEF \ -( \ - add_symbol, "$self, symbol, /", \ - METH_VARARGS, py_binary_format, \ - "Register a new symbol for the format.\n" \ - "\n" \ - "The symbol has to be a pychrysalide.format.BinSymbol instance." \ -) - - ret = PyArg_ParseTuple(args, "O&", convert_to_binary_symbol, &symbol); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - g_object_ref(G_OBJECT(symbol)); - added = g_binary_format_add_symbol(format, symbol); - - result = added ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe représentant un format. * -* args = arguments fournis à l'appel. * -* * -* Description : Retire un symbole de la collection du format binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_remove_symbol(PyObject *self, PyObject *args) -{ - PyObject *result; /* Valeur à retourner */ - GBinSymbol *symbol; /* Enventuel symbole trouvé */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Format de binaire manipulé */ - -#define BINARY_FORMAT_REMOVE_SYMBOL_METHOD PYTHON_METHOD_DEF \ -( \ - remove_symbol, "$self, symbol, /", \ - METH_VARARGS, py_binary_format, \ - "Unregister a symbol from the format.\n" \ - "\n" \ - "The symbol has to be a pychrysalide.format.BinSymbol instance." \ -) - - ret = PyArg_ParseTuple(args, "O&", convert_to_binary_symbol, &symbol); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - g_binary_format_remove_symbol(format, symbol); - - 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 correspondant à une étiquette. * -* * -* Retour : Symbol trouvé si l'opération a été un succès, None sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_find_symbol_by_label(PyObject *self, PyObject *args) -{ - PyObject *result; /* Valeur à retourner */ - const char *label; /* Etiquette à retrouver */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Format de binaire manipulé */ - GBinSymbol *symbol; /* Enventuel symbole trouvé */ - bool found; /* Bilan de la recherche */ - -#define BINARY_FORMAT_FIND_SYMBOL_BY_LABEL_METHOD PYTHON_METHOD_DEF \ -( \ - find_symbol_by_label, "$self, label, /", \ - METH_VARARGS, py_binary_format, \ - "Find the symbol with a given label, provided as a string.\n" \ - "\n" \ - "The result is a pychrysalide.format.BinSymbol instance, or None" \ - " if no symbol was found." \ -) - - ret = PyArg_ParseTuple(args, "s", &label); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - found = g_binary_format_find_symbol_by_label(format, label, &symbol); - - if (found) - { - result = pygobject_new(G_OBJECT(symbol)); - g_object_unref(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 */ - GBinFormat *format; /* Format de binaire manipulé */ - exe_cv_info_t conv; /* Informations de conversion */ - int ret; /* Bilan de lecture des args. */ - GBinSymbol *symbol; /* Enventuel symbole trouvé */ - bool found; /* Bilan de la recherche */ - -#define BINARY_FORMAT_FIND_SYMBOL_AT_METHOD PYTHON_METHOD_DEF \ -( \ - find_symbol_at, "$self, addr, /", \ - METH_VARARGS, py_binary_format, \ - "Find the symbol located at a given address, provided as a" \ - " pychrysalide.arch.vmpa instance.\n" \ - "\n" \ - "The result is a pychrysalide.format.BinSymbol instance, or" \ - " None if no symbol was found." \ -) - - format = G_BIN_FORMAT(pygobject_get(self)); - - conv.format = G_IS_EXE_FORMAT(format) ? G_EXE_FORMAT(format) : NULL; - - ret = PyArg_ParseTuple(args, "O&", convert_to_vmpa_using_executable, &conv); - if (!ret) return NULL; - - found = g_binary_format_find_symbol_at(format, conv.vmpa, &symbol); - - if (found) - { - result = pygobject_new(G_OBJECT(symbol)); - g_object_unref(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_next_symbol_at(PyObject *self, PyObject *args) -{ - PyObject *result; /* Valeur à retourner */ - GBinFormat *format; /* Format de binaire manipulé */ - exe_cv_info_t conv; /* Informations de conversion */ - int ret; /* Bilan de lecture des args. */ - GBinSymbol *symbol; /* Enventuel symbole trouvé */ - bool found; /* Bilan de la recherche */ - -#define BINARY_FORMAT_FIND_NEXT_SYMBOL_AT_METHOD PYTHON_METHOD_DEF \ -( \ - find_next_symbol_at, "$self, addr, /", \ - METH_VARARGS, py_binary_format, \ - "Find the symbol next to the one found at a given address," \ - " provided as a pychrysalide.arch.vmpa instance.\n" \ - "\n" \ - "The result is a pychrysalide.format.BinSymbol instance, or" \ - " None if no symbol was found." \ -) - - format = G_BIN_FORMAT(pygobject_get(self)); - - conv.format = G_IS_EXE_FORMAT(format) ? G_EXE_FORMAT(format) : NULL; - - ret = PyArg_ParseTuple(args, "O&", convert_to_vmpa_using_executable, &conv); - if (!ret) return NULL; - - found = g_binary_format_find_next_symbol_at(format, conv.vmpa, &symbol); - - if (found) - { - result = pygobject_new(G_OBJECT(symbol)); - g_object_unref(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écalage) ou Py_None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_resolve_symbol(PyObject *self, PyObject *args) -{ - PyObject *result; /* Valeur à retourner */ - GBinFormat *format; /* Format de binaire manipulé */ - exe_cv_info_t conv; /* Informations de conversion */ - int strict; /* Tolérance acceptée */ - int ret; /* Bilan de lecture des args. */ - GBinSymbol *symbol; /* Enventuel symbole trouvé */ - phys_t diff; /* Décalage éventuel mesuré */ - bool found; /* Bilan de la recherche */ - -#define BINARY_FORMAT_RESOLVE_SYMBOL_METHOD PYTHON_METHOD_DEF \ -( \ - resolve_symbol, "$self, addr, strict, /", \ - METH_VARARGS, py_binary_format, \ - "Search for a position inside a symbol by a given address.\n" \ - "\n" \ - "The result is a couple of (pychrysalide.format.BinSymbol," \ - " offset) values, or None if no symbol was found. The offset" \ - " is the distance between the start location of the symbol and" \ - " the location provided as argument.\n" \ - "\n" \ - "If the search is run in strict mode, then the offset is" \ - " always 0 upon success." \ -) - - format = G_BIN_FORMAT(pygobject_get(self)); - - conv.format = G_IS_EXE_FORMAT(format) ? G_EXE_FORMAT(format) : NULL; - - ret = PyArg_ParseTuple(args, "O&p", convert_to_vmpa_using_executable, &conv, &strict); - if (!ret) return NULL; - - found = g_binary_format_resolve_symbol(format, conv.vmpa, strict, &symbol, &diff); - - if (found) - { - result = PyTuple_New(2); - PyTuple_SetItem(result, 0, pygobject_new(G_OBJECT(symbol))); - PyTuple_SetItem(result, 1, PyLong_FromUnsignedLongLong(diff)); - - g_object_unref(G_OBJECT(symbol)); - - } - else - { - result = Py_None; - Py_INCREF(result); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit les particularités du format. * -* * -* Retour : Somme de tous les fanions associés au format. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_get_flags(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GBinFormat *format; /* Elément à consulter */ - FormatFlag flags; /* Indications complémentaires */ - -#define BINARY_FORMAT_FLAGS_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - flags, py_binary_format, \ - "Provide all the flags set for a format. The return value" \ - " is of type pychrysalide.format.BinFormat.FormatFlag." \ -) - - format = G_BIN_FORMAT(pygobject_get(self)); - flags = g_binary_format_get_flags(format); - - result = cast_with_constants_group_from_type(get_python_binary_format_type(), "FormatFlag", flags); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Indique le boutisme employé par le format binaire analysé. * -* * -* Retour : Boutisme associé au format. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_get_endianness(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GBinFormat *format; /* Elément à consulter */ - SourceEndian endianness; /* Boutisme du format */ - -#define BINARY_FORMAT_ENDIANNESS_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - endianness, py_binary_format, \ - "Endianness of the format. The return value is of type" \ - " pychrysalide.analysis.BinContent.SourceEndian." \ -) - - format = G_BIN_FORMAT(pygobject_get(self)); - endianness = g_binary_format_get_endianness(format); - - result = cast_with_constants_group_from_type(get_python_binary_content_type(), "SourceEndian", endianness); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = classe représentant un format binaire. * -* closure = adresse non utilisée ici. * -* * -* Description : Fournit la liste de tous les symboles détectés. * -* * -* Retour : Tableau créé ou NULL si aucun symbole trouvé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_get_symbols(PyObject *self, void *closure) -{ - PyObject *result; /* Instance Python à retourner */ - PyTypeObject *iterator_type; /* Type Python de l'itérateur */ - PyObject *args; /* Liste des arguments d'appel */ - -#define BINARY_FORMAT_SYMBOLS_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - symbols, py_binary_format, \ - "Iterable list of all symbols found in the binary format.\n" \ - "\n" \ - "The returned iterator is a pychrysalide.format.SymIterator" \ - " instance and remains valid until the list from the format" \ - " does not change." \ -) - - iterator_type = get_python_sym_iterator_type(); - - args = Py_BuildValue("On", self, 0); - - result = PyObject_CallObject((PyObject *)iterator_type, args); - - Py_DECREF(args); - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* CONSERVATION DES SOUCIS DURANT LE CHARGEMENT */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : self = architecture concernée par la procédure. * -* args = instruction représentant le point de départ. * -* * -* Description : Etend la liste des soucis détectés avec de nouvelles infos. * -* * -* Retour : None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_add_error(PyObject *self, PyObject *args) -{ - BinaryFormatError type; /* Type d'erreur détectée */ - vmpa2t *addr; /* Position d'une erreur */ - const char *desc; /* Description d'une erreur */ - int ret; /* Bilan de lecture des args. */ - GBinFormat *format; /* Format binaire manipulé */ - -#define BINARY_FORMAT_ADD_ERROR_METHOD PYTHON_METHOD_DEF \ -( \ - add_error, "$self, type, addr, desc, /", \ - METH_VARARGS, py_binary_format, \ - "Extend the list of detected errors linked to the format.\n" \ - "\n" \ - "The type of error has to be one of the" \ - " pychrysalide.format.BinFormat.BinaryFormatError flags. The" \ - " location of the error is a pychrysalide.arch.vmpa instance" \ - " and a one-line description should give some details about" \ - " what has failed." \ -) - - ret = PyArg_ParseTuple(args, "O&O&s", convert_to_binary_format_error, &type, convert_any_to_vmpa, &addr, &desc); - if (!ret) return NULL; - - format = G_BIN_FORMAT(pygobject_get(self)); - - g_binary_format_add_error(format, type, addr, desc); - - clean_vmpa_arg(addr); - - Py_RETURN_NONE; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit les éléments concernant tous les soucis détectés. * -* * -* Retour : Liste des erreurs relevées au niveau de l'assembleur. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_binary_format_get_errors(PyObject *self, void *closure) -{ - PyObject *result; /* Instance Python à retourner */ - GBinFormat *format; /* Format binaire manipulé */ - size_t count; /* Nombre d'éléments à traiter */ - size_t i; /* Boucle de parcours */ -#ifndef NDEBUG - bool status; /* Bilan d'un appel */ -#endif - BinaryFormatError type; /* Type d'erreur détectée */ - vmpa2t addr; /* Position d'une erreur */ - char *desc; /* Description d'une erreur */ - PyObject *py_type; /* Version Python du type */ - PyObject *error; /* Nouvelle erreur à rajouter */ - -#define BINARY_FORMAT_ERRORS_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - errors, py_binary_format, \ - "List of all detected errors which occurred while loading the binary.\n" \ - "\n" \ - "The result is a tuple of (pychrysalide.format.BinFormat.BinaryFormatError," \ - " pychrysalide.arch.vmpa, string) values, providing a location and a" \ - " description for each error." \ -) - - format = G_BIN_FORMAT(pygobject_get(self)); - - g_binary_format_lock_errors(format); - - count = g_binary_format_count_errors(format); - - result = PyTuple_New(count); - - for (i = 0; i < count; i++) - { -#ifndef NDEBUG - status = g_binary_format_get_error(format, i, &type, &addr, &desc); - assert(status); -#else - g_binary_format_get_error(format, i, &type, &addr, &desc); -#endif - - py_type = cast_with_constants_group_from_type(get_python_binary_format_type(), "BinaryFormatError", type); - error = Py_BuildValue("OO&s", py_type, build_from_internal_vmpa, &addr, desc); - Py_DECREF(py_type); - - PyTuple_SetItem(result, i, error); - - } - - g_binary_format_unlock_errors(format); - - 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[] = { - BINARY_FORMAT_SET_FLAG_METHOD, - BINARY_FORMAT_UNSET_FLAG_METHOD, - BINARY_FORMAT_HAS_FLAG_METHOD, - BINARY_FORMAT_REGISTER_CODE_POINT_METHOD, - BINARY_FORMAT_ADD_SYMBOL_METHOD, - BINARY_FORMAT_REMOVE_SYMBOL_METHOD, - BINARY_FORMAT_FIND_SYMBOL_BY_LABEL_METHOD, - BINARY_FORMAT_FIND_SYMBOL_AT_METHOD, - BINARY_FORMAT_FIND_NEXT_SYMBOL_AT_METHOD, - BINARY_FORMAT_RESOLVE_SYMBOL_METHOD, - BINARY_FORMAT_ADD_ERROR_METHOD, - { NULL } - }; - - static PyGetSetDef py_bin_format_getseters[] = { - BINARY_FORMAT_FLAGS_ATTRIB, - BINARY_FORMAT_ENDIANNESS_ATTRIB, - BINARY_FORMAT_SYMBOLS_ATTRIB, - BINARY_FORMAT_ERRORS_ATTRIB, - { NULL } - }; - - static PyTypeObject py_bin_format_type = { - - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "pychrysalide.format.BinFormat", - .tp_basicsize = sizeof(PyGObject), - - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, - - .tp_doc = BINARY_FORMAT_DOC, - - .tp_methods = py_bin_format_methods, - .tp_getset = py_bin_format_getseters, - - .tp_init = py_binary_format_init, - .tp_new = py_binary_format_new, - - }; - - 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 ensure_python_binary_format_is_registered(void) -{ - PyTypeObject *type; /* Type Python 'BinFormat' */ - PyObject *module; /* Module à recompléter */ - PyObject *dict; /* Dictionnaire du module */ - - type = get_python_binary_format_type(); - - if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) - { - module = get_access_to_python_module("pychrysalide.format"); - - dict = PyModule_GetDict(module); - - if (!ensure_python_known_format_is_registered()) - return false; - - if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type)) - return false; - - if (!define_binary_format_constants(type)) - return false; - - } - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : arg = argument quelconque à tenter de convertir. * -* dst = destination des valeurs récupérées en cas de succès. * -* * -* Description : Tente de convertir en format de binaire. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_binary_format(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - - result = PyObject_IsInstance(arg, (PyObject *)get_python_binary_format_type()); - - switch (result) - { - case -1: - /* L'exception est déjà fixée par Python */ - result = 0; - break; - - case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to binary format"); - break; - - case 1: - *((GBinFormat **)dst) = G_BIN_FORMAT(pygobject_get(arg)); - break; - - default: - assert(false); - break; - - } - - return result; - -} diff --git a/plugins/pychrysalide/format/format.h b/plugins/pychrysalide/format/format.h deleted file mode 100644 index 04ac9e3..0000000 --- a/plugins/pychrysalide/format/format.h +++ /dev/null @@ -1,59 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * format.h - prototypes pour l'équivalent Python du fichier "format/format.h" - * - * Copyright (C) 2018-2020 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef _PLUGINS_PYCHRYSALIDE_FORMAT_FORMAT_H -#define _PLUGINS_PYCHRYSALIDE_FORMAT_FORMAT_H - - -#include -#include - - - -/* ------------------------ PARCOURS DE SYMBOLES DE BINAIRES ------------------------ */ - - -/* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_binary_symbol_iterator_type(void); - -/* Prend en charge l'objet 'pychrysalide...BinSymbolIterator'. */ -bool ensure_python_binary_symbol_iterator_is_registered(void); - - - -/* ---------------------------- FORMAT BINAIRE GENERIQUE ---------------------------- */ - - -/* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_binary_format_type(void); - -/* Prend en charge l'objet 'pychrysalide.format.BinFormat'. */ -bool ensure_python_binary_format_is_registered(void); - -/* Tente de convertir en format de binaire. */ -int convert_to_binary_format(PyObject *, void *); - - - -#endif /* _PLUGINS_PYCHRYSALIDE_FORMAT_FORMAT_H */ diff --git a/plugins/pychrysalide/format/program.c b/plugins/pychrysalide/format/program.c new file mode 100644 index 0000000..82c6c33 --- /dev/null +++ b/plugins/pychrysalide/format/program.c @@ -0,0 +1,1208 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.c - équivalent Python du fichier "format/format.c" + * + * Copyright (C) 2018-2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "format.h" + + +#include + + +#include +#include +#include + + +#include "constants.h" +#include "executable.h" +#include "known.h" +#include "symbol.h" +#include "symiter.h" +#include "../access.h" +#include "../helpers.h" +#include "../analysis/constants.h" +#include "../analysis/content.h" +#include "../arch/vmpa.h" +#include "../arch/constants.h" + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_binary_format_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise la classe des descriptions de fichier binaire. */ +static void py_binary_format_init_gclass(GBinFormatClass *, gpointer); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_binary_format_init(PyObject *, PyObject *, PyObject *); + +/* Indique le boutisme employé par le format binaire analysé. */ +static SourceEndian py_binary_format_get_endianness_wrapper(const GBinFormat *); + + + +/* ---------------------------- FORMAT BINAIRE GENERIQUE ---------------------------- */ + + +/* Ajoute une information complémentaire à un format. */ +static PyObject *py_binary_format_set_flag(PyObject *, PyObject *); + +/* Retire une information complémentaire à un format. */ +static PyObject *py_binary_format_unset_flag(PyObject *, PyObject *); + +/* Détermine si un format possède un fanion particulier. */ +static PyObject *py_binary_format_has_flag(PyObject *, PyObject *); + +/* Enregistre une adresse comme début d'une zone de code. */ +static PyObject *py_binary_format_register_code_point(PyObject *, PyObject *); + +/* Ajoute un symbole à la collection du format binaire. */ +static PyObject *py_binary_format_add_symbol(PyObject *, PyObject *); + +/* Retire un symbole de la collection du format binaire. */ +static PyObject *py_binary_format_remove_symbol(PyObject *, PyObject *); + +/* 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 les particularités du format. */ +static PyObject *py_binary_format_get_flags(PyObject *, void *); + +/* Indique le boutisme employé par le format binaire analysé. */ +static PyObject *py_binary_format_get_endianness(PyObject *, void *); + +/* Fournit la liste de tous les symboles détectés. */ +static PyObject *py_binary_format_get_symbols(PyObject *, void *); + + + +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ + + +/* Etend la liste des soucis détectés avec de nouvelles infos. */ +static PyObject *py_binary_format_add_error(PyObject *, PyObject *); + +/* Fournit les éléments concernant tous les soucis détectés. */ +static PyObject *py_binary_format_get_errors(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = get_python_known_format_type(); + + if (type == base) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } + + /* Mise en place d'un type dédié */ + + first_time = (g_type_from_name(type->tp_name) == 0); + + gtype = build_dynamic_type(G_TYPE_BIN_FORMAT, type->tp_name, + (GClassInitFunc)py_binary_format_init_gclass, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe générique des processeurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_binary_format_init_gclass(GBinFormatClass *class, gpointer unused) +{ + class->get_endian = py_binary_format_get_endianness_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_binary_format_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define BINARY_FORMAT_DOC \ + "The BinFormat class is the major poart of binary format support." \ + " It is the core class used by loading most of the binary files.\n" \ + "\n" \ + "One item has to be defined as class attribute in the final" \ + " class:\n" \ + "* *_endianness*: a pychrysalide.analysis.BinContent.SourceEndian" \ + " value indicating the endianness of the format.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " no particular argument." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description du format connu à consulter. * +* * +* Description : Indique le boutisme employé par le format binaire analysé. * +* * +* Retour : Boutisme associé au format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static SourceEndian py_binary_format_get_endianness_wrapper(const GBinFormat *format) +{ + SourceEndian result; /* Boutisme à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Valeur retournée */ + int ret; /* Bilan d'une conversion */ + + result = SRE_LITTLE; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(format)); + + if (PyObject_HasAttrString(pyobj, "_endianness")) + { + pyret = PyObject_GetAttrString(pyobj, "_endianness"); + + if (pyret != NULL) + { + ret = convert_to_source_endian(pyret, &result); + + if (ret != 1) + result = SRE_LITTLE; + + Py_DECREF(pyret); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/* ---------------------------------------------------------------------------------- */ +/* FORMAT BINAIRE GENERIQUE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Ajoute une information complémentaire à un format. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_set_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Propriété à traiter */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Elément à manipuler */ + bool status; /* Bilan de l'opération */ + +#define BINARY_FORMAT_SET_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + set_flag, "$self, flag, /", \ + METH_VARARGS, py_binary_format, \ + "Add a property from a binary format.\n" \ + "\n" \ + "This property is one of the values listed in the" \ + " of pychrysalide.format.BinFormat.FormatFlag enumeration.\n" \ + "\n" \ + "If the flag was not set before the operation, True is" \ + " returned, else the result is False." \ +) + + ret = PyArg_ParseTuple(args, "I", &flag); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + status = g_binary_format_set_flag(format, flag); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Retire une information complémentaire à un format. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_unset_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Propriété à traiter */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Elément à manipuler */ + bool status; /* Bilan de l'opération */ + +#define BINARY_FORMAT_UNSET_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + unset_flag, "$self, flag, /", \ + METH_VARARGS, py_binary_format, \ + "Remove a property from a binary format.\n" \ + "\n" \ + "This property is one of the values listed in the" \ + " of pychrysalide.format.BinFormat.FormatFlag enumeration.\n" \ + "\n" \ + "If the flag was not set before the operation, False is" \ + " returned, else the result is True." \ +) + + ret = PyArg_ParseTuple(args, "I", &flag); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + status = g_binary_format_unset_flag(format, flag); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Détermine si un format possède un fanion particulier. * +* * +* Retour : Bilan de la détection. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_has_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned int flag; /* Propriété à traiter */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Elément à manipuler */ + bool status; /* Bilan de l'opération */ + +#define BINARY_FORMAT_HAS_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + has_flag, "$self, flag, /", \ + METH_VARARGS, py_binary_format, \ + "Test if a binary format has a given property.\n" \ + "\n" \ + "This property is one of the values listed in the" \ + " of pychrysalide.format.BinFormat.FormatFlag enumeration.\n" \ + "\n" \ + "The result is a boolean value." \ +) + + ret = PyArg_ParseTuple(args, "I", &flag); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + status = g_binary_format_has_flag(format, flag); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Enregistre une adresse comme début d'une zone de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_register_code_point(PyObject *self, PyObject *args) +{ + unsigned long long pt; /* Adresse virtuelle du point */ + DisassPriorityLevel level; /* Nature du point fourni */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + +#define BINARY_FORMAT_REGISTER_CODE_POINT_METHOD PYTHON_METHOD_DEF \ +( \ + register_code_point, "$self, point, level, /", \ + METH_VARARGS, py_binary_format, \ + "Register a virtual address as entry point or basic point.\n" \ + "\n" \ + "The point is an integer value for the virtual memory location" \ + " of the new (entry) point. The type of this entry has to be a" \ + " pychrysalide.arch.ProcContext.DisassPriorityLevel value." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &pt, convert_to_disass_priority_level, &level); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + g_binary_format_register_code_point(format, pt, level); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Ajoute un symbole à la collection du format binaire. * +* * +* Retour : True si le symbole était bien localisé et a été inséré. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_add_symbol(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + bool added; /* Bilan de l'appel interne */ + +#define BINARY_FORMAT_ADD_SYMBOL_METHOD PYTHON_METHOD_DEF \ +( \ + add_symbol, "$self, symbol, /", \ + METH_VARARGS, py_binary_format, \ + "Register a new symbol for the format.\n" \ + "\n" \ + "The symbol has to be a pychrysalide.format.BinSymbol instance." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_binary_symbol, &symbol); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + g_object_ref(G_OBJECT(symbol)); + added = g_binary_format_add_symbol(format, symbol); + + result = added ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Retire un symbole de la collection du format binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_remove_symbol(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + +#define BINARY_FORMAT_REMOVE_SYMBOL_METHOD PYTHON_METHOD_DEF \ +( \ + remove_symbol, "$self, symbol, /", \ + METH_VARARGS, py_binary_format, \ + "Unregister a symbol from the format.\n" \ + "\n" \ + "The symbol has to be a pychrysalide.format.BinSymbol instance." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_binary_symbol, &symbol); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + g_binary_format_remove_symbol(format, symbol); + + 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 correspondant à une étiquette. * +* * +* Retour : Symbol trouvé si l'opération a été un succès, None sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_find_symbol_by_label(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + const char *label; /* Etiquette à retrouver */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format de binaire manipulé */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + bool found; /* Bilan de la recherche */ + +#define BINARY_FORMAT_FIND_SYMBOL_BY_LABEL_METHOD PYTHON_METHOD_DEF \ +( \ + find_symbol_by_label, "$self, label, /", \ + METH_VARARGS, py_binary_format, \ + "Find the symbol with a given label, provided as a string.\n" \ + "\n" \ + "The result is a pychrysalide.format.BinSymbol instance, or None" \ + " if no symbol was found." \ +) + + ret = PyArg_ParseTuple(args, "s", &label); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + found = g_binary_format_find_symbol_by_label(format, label, &symbol); + + if (found) + { + result = pygobject_new(G_OBJECT(symbol)); + g_object_unref(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 */ + GBinFormat *format; /* Format de binaire manipulé */ + exe_cv_info_t conv; /* Informations de conversion */ + int ret; /* Bilan de lecture des args. */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + bool found; /* Bilan de la recherche */ + +#define BINARY_FORMAT_FIND_SYMBOL_AT_METHOD PYTHON_METHOD_DEF \ +( \ + find_symbol_at, "$self, addr, /", \ + METH_VARARGS, py_binary_format, \ + "Find the symbol located at a given address, provided as a" \ + " pychrysalide.arch.vmpa instance.\n" \ + "\n" \ + "The result is a pychrysalide.format.BinSymbol instance, or" \ + " None if no symbol was found." \ +) + + format = G_BIN_FORMAT(pygobject_get(self)); + + conv.format = G_IS_EXE_FORMAT(format) ? G_EXE_FORMAT(format) : NULL; + + ret = PyArg_ParseTuple(args, "O&", convert_to_vmpa_using_executable, &conv); + if (!ret) return NULL; + + found = g_binary_format_find_symbol_at(format, conv.vmpa, &symbol); + + if (found) + { + result = pygobject_new(G_OBJECT(symbol)); + g_object_unref(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_next_symbol_at(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + GBinFormat *format; /* Format de binaire manipulé */ + exe_cv_info_t conv; /* Informations de conversion */ + int ret; /* Bilan de lecture des args. */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + bool found; /* Bilan de la recherche */ + +#define BINARY_FORMAT_FIND_NEXT_SYMBOL_AT_METHOD PYTHON_METHOD_DEF \ +( \ + find_next_symbol_at, "$self, addr, /", \ + METH_VARARGS, py_binary_format, \ + "Find the symbol next to the one found at a given address," \ + " provided as a pychrysalide.arch.vmpa instance.\n" \ + "\n" \ + "The result is a pychrysalide.format.BinSymbol instance, or" \ + " None if no symbol was found." \ +) + + format = G_BIN_FORMAT(pygobject_get(self)); + + conv.format = G_IS_EXE_FORMAT(format) ? G_EXE_FORMAT(format) : NULL; + + ret = PyArg_ParseTuple(args, "O&", convert_to_vmpa_using_executable, &conv); + if (!ret) return NULL; + + found = g_binary_format_find_next_symbol_at(format, conv.vmpa, &symbol); + + if (found) + { + result = pygobject_new(G_OBJECT(symbol)); + g_object_unref(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écalage) ou Py_None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_resolve_symbol(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + GBinFormat *format; /* Format de binaire manipulé */ + exe_cv_info_t conv; /* Informations de conversion */ + int strict; /* Tolérance acceptée */ + int ret; /* Bilan de lecture des args. */ + GBinSymbol *symbol; /* Enventuel symbole trouvé */ + phys_t diff; /* Décalage éventuel mesuré */ + bool found; /* Bilan de la recherche */ + +#define BINARY_FORMAT_RESOLVE_SYMBOL_METHOD PYTHON_METHOD_DEF \ +( \ + resolve_symbol, "$self, addr, strict, /", \ + METH_VARARGS, py_binary_format, \ + "Search for a position inside a symbol by a given address.\n" \ + "\n" \ + "The result is a couple of (pychrysalide.format.BinSymbol," \ + " offset) values, or None if no symbol was found. The offset" \ + " is the distance between the start location of the symbol and" \ + " the location provided as argument.\n" \ + "\n" \ + "If the search is run in strict mode, then the offset is" \ + " always 0 upon success." \ +) + + format = G_BIN_FORMAT(pygobject_get(self)); + + conv.format = G_IS_EXE_FORMAT(format) ? G_EXE_FORMAT(format) : NULL; + + ret = PyArg_ParseTuple(args, "O&p", convert_to_vmpa_using_executable, &conv, &strict); + if (!ret) return NULL; + + found = g_binary_format_resolve_symbol(format, conv.vmpa, strict, &symbol, &diff); + + if (found) + { + result = PyTuple_New(2); + PyTuple_SetItem(result, 0, pygobject_new(G_OBJECT(symbol))); + PyTuple_SetItem(result, 1, PyLong_FromUnsignedLongLong(diff)); + + g_object_unref(G_OBJECT(symbol)); + + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les particularités du format. * +* * +* Retour : Somme de tous les fanions associés au format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_get_flags(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GBinFormat *format; /* Elément à consulter */ + FormatFlag flags; /* Indications complémentaires */ + +#define BINARY_FORMAT_FLAGS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + flags, py_binary_format, \ + "Provide all the flags set for a format. The return value" \ + " is of type pychrysalide.format.BinFormat.FormatFlag." \ +) + + format = G_BIN_FORMAT(pygobject_get(self)); + flags = g_binary_format_get_flags(format); + + result = cast_with_constants_group_from_type(get_python_binary_format_type(), "FormatFlag", flags); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le boutisme employé par le format binaire analysé. * +* * +* Retour : Boutisme associé au format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_get_endianness(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GBinFormat *format; /* Elément à consulter */ + SourceEndian endianness; /* Boutisme du format */ + +#define BINARY_FORMAT_ENDIANNESS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + endianness, py_binary_format, \ + "Endianness of the format. The return value is of type" \ + " pychrysalide.analysis.BinContent.SourceEndian." \ +) + + format = G_BIN_FORMAT(pygobject_get(self)); + endianness = g_binary_format_get_endianness(format); + + result = cast_with_constants_group_from_type(get_python_binary_content_type(), "SourceEndian", endianness); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format binaire. * +* closure = adresse non utilisée ici. * +* * +* Description : Fournit la liste de tous les symboles détectés. * +* * +* Retour : Tableau créé ou NULL si aucun symbole trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_get_symbols(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + PyTypeObject *iterator_type; /* Type Python de l'itérateur */ + PyObject *args; /* Liste des arguments d'appel */ + +#define BINARY_FORMAT_SYMBOLS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + symbols, py_binary_format, \ + "Iterable list of all symbols found in the binary format.\n" \ + "\n" \ + "The returned iterator is a pychrysalide.format.SymIterator" \ + " instance and remains valid until the list from the format" \ + " does not change." \ +) + + iterator_type = get_python_sym_iterator_type(); + + args = Py_BuildValue("On", self, 0); + + result = PyObject_CallObject((PyObject *)iterator_type, args); + + Py_DECREF(args); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONSERVATION DES SOUCIS DURANT LE CHARGEMENT */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = architecture concernée par la procédure. * +* args = instruction représentant le point de départ. * +* * +* Description : Etend la liste des soucis détectés avec de nouvelles infos. * +* * +* Retour : None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_add_error(PyObject *self, PyObject *args) +{ + BinaryFormatError type; /* Type d'erreur détectée */ + vmpa2t *addr; /* Position d'une erreur */ + const char *desc; /* Description d'une erreur */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format binaire manipulé */ + +#define BINARY_FORMAT_ADD_ERROR_METHOD PYTHON_METHOD_DEF \ +( \ + add_error, "$self, type, addr, desc, /", \ + METH_VARARGS, py_binary_format, \ + "Extend the list of detected errors linked to the format.\n" \ + "\n" \ + "The type of error has to be one of the" \ + " pychrysalide.format.BinFormat.BinaryFormatError flags. The" \ + " location of the error is a pychrysalide.arch.vmpa instance" \ + " and a one-line description should give some details about" \ + " what has failed." \ +) + + ret = PyArg_ParseTuple(args, "O&O&s", convert_to_binary_format_error, &type, convert_any_to_vmpa, &addr, &desc); + if (!ret) return NULL; + + format = G_BIN_FORMAT(pygobject_get(self)); + + g_binary_format_add_error(format, type, addr, desc); + + clean_vmpa_arg(addr); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les éléments concernant tous les soucis détectés. * +* * +* Retour : Liste des erreurs relevées au niveau de l'assembleur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_format_get_errors(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GBinFormat *format; /* Format binaire manipulé */ + size_t count; /* Nombre d'éléments à traiter */ + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + bool status; /* Bilan d'un appel */ +#endif + BinaryFormatError type; /* Type d'erreur détectée */ + vmpa2t addr; /* Position d'une erreur */ + char *desc; /* Description d'une erreur */ + PyObject *py_type; /* Version Python du type */ + PyObject *error; /* Nouvelle erreur à rajouter */ + +#define BINARY_FORMAT_ERRORS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + errors, py_binary_format, \ + "List of all detected errors which occurred while loading the binary.\n" \ + "\n" \ + "The result is a tuple of (pychrysalide.format.BinFormat.BinaryFormatError," \ + " pychrysalide.arch.vmpa, string) values, providing a location and a" \ + " description for each error." \ +) + + format = G_BIN_FORMAT(pygobject_get(self)); + + g_binary_format_lock_errors(format); + + count = g_binary_format_count_errors(format); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { +#ifndef NDEBUG + status = g_binary_format_get_error(format, i, &type, &addr, &desc); + assert(status); +#else + g_binary_format_get_error(format, i, &type, &addr, &desc); +#endif + + py_type = cast_with_constants_group_from_type(get_python_binary_format_type(), "BinaryFormatError", type); + error = Py_BuildValue("OO&s", py_type, build_from_internal_vmpa, &addr, desc); + Py_DECREF(py_type); + + PyTuple_SetItem(result, i, error); + + } + + g_binary_format_unlock_errors(format); + + 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[] = { + BINARY_FORMAT_SET_FLAG_METHOD, + BINARY_FORMAT_UNSET_FLAG_METHOD, + BINARY_FORMAT_HAS_FLAG_METHOD, + BINARY_FORMAT_REGISTER_CODE_POINT_METHOD, + BINARY_FORMAT_ADD_SYMBOL_METHOD, + BINARY_FORMAT_REMOVE_SYMBOL_METHOD, + BINARY_FORMAT_FIND_SYMBOL_BY_LABEL_METHOD, + BINARY_FORMAT_FIND_SYMBOL_AT_METHOD, + BINARY_FORMAT_FIND_NEXT_SYMBOL_AT_METHOD, + BINARY_FORMAT_RESOLVE_SYMBOL_METHOD, + BINARY_FORMAT_ADD_ERROR_METHOD, + { NULL } + }; + + static PyGetSetDef py_bin_format_getseters[] = { + BINARY_FORMAT_FLAGS_ATTRIB, + BINARY_FORMAT_ENDIANNESS_ATTRIB, + BINARY_FORMAT_SYMBOLS_ATTRIB, + BINARY_FORMAT_ERRORS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_bin_format_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.format.BinFormat", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = BINARY_FORMAT_DOC, + + .tp_methods = py_bin_format_methods, + .tp_getset = py_bin_format_getseters, + + .tp_init = py_binary_format_init, + .tp_new = py_binary_format_new, + + }; + + 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 ensure_python_binary_format_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'BinFormat' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_binary_format_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.format"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_known_format_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type)) + return false; + + if (!define_binary_format_constants(type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en format de binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_binary_format(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_binary_format_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to binary format"); + break; + + case 1: + *((GBinFormat **)dst) = G_BIN_FORMAT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/format/program.h b/plugins/pychrysalide/format/program.h new file mode 100644 index 0000000..04ac9e3 --- /dev/null +++ b/plugins/pychrysalide/format/program.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.h - prototypes pour l'équivalent Python du fichier "format/format.h" + * + * Copyright (C) 2018-2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_FORMAT_FORMAT_H +#define _PLUGINS_PYCHRYSALIDE_FORMAT_FORMAT_H + + +#include +#include + + + +/* ------------------------ PARCOURS DE SYMBOLES DE BINAIRES ------------------------ */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_binary_symbol_iterator_type(void); + +/* Prend en charge l'objet 'pychrysalide...BinSymbolIterator'. */ +bool ensure_python_binary_symbol_iterator_is_registered(void); + + + +/* ---------------------------- FORMAT BINAIRE GENERIQUE ---------------------------- */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_binary_format_type(void); + +/* Prend en charge l'objet 'pychrysalide.format.BinFormat'. */ +bool ensure_python_binary_format_is_registered(void); + +/* Tente de convertir en format de binaire. */ +int convert_to_binary_format(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_FORMAT_FORMAT_H */ diff --git a/src/format/Makefile.am b/src/format/Makefile.am index 305cd92..dcd3567 100644 --- a/src/format/Makefile.am +++ b/src/format/Makefile.am @@ -1,23 +1,24 @@ noinst_LTLIBRARIES = libformat.la -libformat_la_SOURCES = \ - debuggable-int.h \ - debuggable.h debuggable.c \ - executable-int.h executable-int.c \ - executable.h executable.c \ - flat-int.h \ - flat.h flat.c \ - format-int.h \ - format.h format.c \ - known-int.h \ - known.h known.c \ - preload-int.h \ - preload.h preload.c \ - strsym.h strsym.c \ - symiter.h symiter.c \ - symbol-int.h \ - symbol.h symbol.c +libformat_la_SOURCES = +# \ +# debuggable-int.h \ +# debuggable.h debuggable.c \ +# executable-int.h executable-int.c \ +# executable.h executable.c \ +# flat-int.h \ +# flat.h flat.c \ +# program-int.h \ +# program.h program.c \ +# known-int.h \ +# known.h known.c \ +# preload-int.h \ +# preload.h preload.c \ +# strsym.h strsym.c \ +# symiter.h symiter.c \ +# symbol-int.h \ +# symbol.h symbol.c libformat_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) diff --git a/src/format/format-int.h b/src/format/format-int.h deleted file mode 100644 index f18bb24..0000000 --- a/src/format/format-int.h +++ /dev/null @@ -1,160 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * format-int.h - prototypes utiles aux formats binaires - * - * Copyright (C) 2009-2018 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see . - */ - - -#ifndef _FORMAT_FORMAT_INT_H -#define _FORMAT_FORMAT_INT_H - - -#include "format.h" - - -#include "known-int.h" -#include "preload.h" -#include "../glibext/objhole.h" -#include "../mangling/demangler.h" - - - -/* ------------------------ TRAITEMENT INDIVIDUEL DE FORMATS ------------------------ */ - - -/* Indique le boutisme employé par le format binaire analysé. */ -typedef SourceEndian (* format_get_endian_fc) (const GBinFormat *); - -/* Rythme des allocations pour les entrées de code */ -#define EXTRA_POINT_BLOCK 20 - - -/* Informations glissées dans la structure GObject de GArchOperand */ -typedef struct _fmt_extra_data_t -{ - FormatFlag flags; /* Informations complémentaires*/ - -} fmt_extra_data_t; - -/* Encapsulation avec un verrou d'accès */ -typedef union _fmt_obj_extra_t -{ - fmt_extra_data_t data; /* Données embarquées */ - lockable_obj_extra_t lockable; /* Gestion d'accès aux fanions */ - -} fmt_obj_extra_t; - - -/* Description d'une erreur */ -typedef struct _fmt_error -{ - BinaryFormatError type; /* Type d'erreur */ - - vmpa2t addr; /* Localisation du problème */ - char *desc; /* Description du soucis */ - -} fmt_error; - -/* Format binaire générique (instance) */ -struct _GBinFormat -{ - GKnownFormat parent; /* A laisser en premier */ - -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ - - /** - * L'inclusion des informations suivantes dépend de l'architecture. - * - * Si la structure GObject possède un trou, on remplit de préférence - * ce dernier. - */ - - fmt_obj_extra_t extra; /* Externalisation embarquée */ - -#endif - - virt_t *start_points[DPL_COUNT]; /* Départ de désassemblage */ - size_t pt_allocated[DPL_COUNT]; /* Taille d'inscription allouée*/ - size_t pt_count[DPL_COUNT]; /* Nombre de points enregistrés*/ - GRWLock pt_lock; /* Accès à la liste des points */ - - GPreloadInfo *info; /* Préchargements du format */ - - GCompDemangler *demangler; /* Décodage de noms privilégié */ - - GBinSymbol **symbols; /* Liste des symboles trouvés */ - size_t sym_count; /* Quantité de ces symboles */ - unsigned int sym_stamp; /* Marque de suivi des modifs */ - GRWLock syms_lock; /* Accès à la liste de symboles*/ -#ifndef NDEBUG - gint sym_locked; /* Statut d'accès à la liste */ -#endif - - fmt_error *errors; /* Liste d'erreurs rencontrées */ - size_t error_count; /* Taille de cette liste */ - GMutex error_mutex; /* Verrou pour l'accès */ -#ifndef NDEBUG - gint error_locked; /* Statut d'accès à la liste */ -#endif - -}; - -/* Format binaire générique (classe) */ -struct _GBinFormatClass -{ - GKnownFormatClass parent; /* A laisser en premier */ - - format_get_endian_fc get_endian; /* Boutisme employé */ - - /* Signaux */ - - void (* symbol_added) (GBinFormat *, GBinSymbol *); - void (* symbol_removed) (GBinFormat *, GBinSymbol *); - -}; - - -/** - * Accès aux informations éventuellement déportées. - */ - -#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ - -# define GET_BIN_FORMAT_EXTRA(fmt) (fmt_extra_data_t *)&fmt->extra - -#else - -# define GET_BIN_FORMAT_EXTRA(fmt) GET_GOBJECT_EXTRA(G_OBJECT(fmt), fmt_extra_data_t) - -#endif - - - -/* ------------------------------ DECODAGE DE SYMBOLES ------------------------------ */ - - -/* Décode une chaîne de caractères donnée en type. */ -GDataType *g_binary_format_decode_type(const GBinFormat *, const char *); - -/* Décode une chaîne de caractères donnée en routine. */ -GBinRoutine *g_binary_format_decode_routine(const GBinFormat *, const char *); - - - -#endif /* _FORMAT_FORMAT_INT_H */ diff --git a/src/format/format.c b/src/format/format.c deleted file mode 100644 index d126236..0000000 --- a/src/format/format.c +++ /dev/null @@ -1,1920 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * format.c - support des différents formats binaires - * - * Copyright (C) 2009-2020 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see . - */ - - -#include "format.h" - - -#include -#include -#include - - -#include "format-int.h" -#include "preload.h" -#include "../arch/processor.h" -#include "../common/sort.h" -#include "../core/demanglers.h" -#include "../plugins/pglist.h" - - - -/* Initialise la classe des formats binaires génériques. */ -static void g_binary_format_class_init(GBinFormatClass *); - -/* Initialise une instance de format binaire générique. */ -static void g_binary_format_init(GBinFormat *); - -/* Supprime toutes les références externes. */ -static void g_binary_format_dispose(GBinFormat *); - -/* Procède à la libération totale de la mémoire. */ -static void g_binary_format_finalize(GBinFormat *); - -/* Charge les plages de couvertures depuis une mémoire tampon. */ -static bool g_binary_format_load_start_points(GBinFormat *, packed_buffer_t *); - -/* Sauvegarde les points de départ enregistrés pour un format. */ -static bool g_binary_format_store_start_points(GBinFormat *, packed_buffer_t *); - - - -/* ---------------------- RASSEMBLEMENT ET GESTION DE SYMBOLES ---------------------- */ - - -/* Retire un symbole de la collection du format binaire. */ -static void _g_binary_format_remove_symbol(GBinFormat *, size_t); - -/* Recherche le symbole associé à une adresse. */ -static bool _g_binary_format_find_symbol(const GBinFormat *, const vmpa2t *, __compar_fn_t, size_t *, GBinSymbol **); - -/* Recherche un symbole particulier. */ -static bool __g_binary_format_find_symbol(const GBinFormat *, const void *, __compar_fn_t, size_t *, GBinSymbol **); - - - -/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ - - -/* Charge les erreurs de chargement depuis une mémoire tampon. */ -static bool g_binary_format_load_errors(GBinFormat *, packed_buffer_t *); - -/* Sauvegarde les erreurs de chargement dans une mémoire tampon. */ -static bool g_binary_format_store_errors(GBinFormat *, packed_buffer_t *); - - - -/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ - - -/* Charge un format depuis une mémoire tampon. */ -static bool g_binary_format_load(GBinFormat *, GObjectStorage *, packed_buffer_t *); - -/* Sauvegarde un format dans une mémoire tampon. */ -static bool g_binary_format_store(GBinFormat *, GObjectStorage *, packed_buffer_t *); - - - - - -/* Indique le type défini pour un format binaire générique. */ -G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_KNOWN_FORMAT); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des formats binaires génériques. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_format_class_init(GBinFormatClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GKnownFormatClass *known; /* Version de classe parente */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_format_dispose; - object->finalize = (GObjectFinalizeFunc)g_binary_format_finalize; - - known = G_KNOWN_FORMAT_CLASS(klass); - - known->load = (load_known_fc)g_binary_format_load; - known->store = (load_known_fc)g_binary_format_store; - - g_signal_new("symbol-added", - G_TYPE_BIN_FORMAT, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBinFormatClass, symbol_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - g_signal_new("symbol-removed", - G_TYPE_BIN_FORMAT, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBinFormatClass, symbol_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - -} - - -/****************************************************************************** -* * -* Paramètres : format = instance à initialiser. * -* * -* Description : Initialise une instance de format binaire générique. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_format_init(GBinFormat *format) -{ - fmt_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - INIT_GOBJECT_EXTRA_LOCK(extra); - - g_rw_lock_init(&format->pt_lock); - - format->info = g_preload_info_new(); - - format->demangler = NULL; - - g_rw_lock_init(&format->syms_lock); -#ifndef NDEBUG - g_atomic_int_set(&format->sym_locked, 0); -#endif - - format->errors = NULL; - format->error_count = 0; - g_mutex_init(&format->error_mutex); -#ifndef NDEBUG - g_atomic_int_set(&format->error_locked, 0); -#endif - -} - - -/****************************************************************************** -* * -* Paramètres : format = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_format_dispose(GBinFormat *format) -{ - size_t i; /* Boucle de parcours */ - - g_rw_lock_clear(&format->pt_lock); - - g_clear_object(&format->info); - - g_clear_object(&format->demangler); - - for (i = 0; i < format->sym_count; i++) - g_clear_object(&format->symbols[i]); - - g_rw_lock_clear(&format->syms_lock); - - g_mutex_clear(&format->error_mutex); - - G_OBJECT_CLASS(g_binary_format_parent_class)->dispose(G_OBJECT(format)); - -} - - -/****************************************************************************** -* * -* Paramètres : format = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_binary_format_finalize(GBinFormat *format) -{ - DisassPriorityLevel i; /* Boucle de parcours #1 */ - size_t k; /* Boucle de parcours #2 */ - - for (i = 0; i < DPL_COUNT; i++) - if (format->start_points[i] != NULL) - free(format->start_points[i]); - - if (format->symbols != NULL) - free(format->symbols); - - if (format->errors != NULL) - { - for (k = 0; k < format->error_count; k++) - if (format->errors[k].desc != NULL) - free(format->errors[k].desc); - - free(format->errors); - - } - - G_OBJECT_CLASS(g_binary_format_parent_class)->finalize(G_OBJECT(format)); - -} - - -/****************************************************************************** -* * -* Paramètres : format = format à venir modifier. * -* flag = drapeau d'information complémentaire à planter. * -* * -* Description : Ajoute une information complémentaire à un format. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_set_flag(GBinFormat *format, FormatFlag flag) -{ - bool result; /* Bilan à retourner */ - fmt_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - LOCK_GOBJECT_EXTRA(extra); - - result = !(extra->flags & flag); - - extra->flags |= flag; - - UNLOCK_GOBJECT_EXTRA(extra); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format à venir modifier. * -* flag = drapeau d'information complémentaire à planter. * -* * -* Description : Retire une information complémentaire à un format. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_unset_flag(GBinFormat *format, FormatFlag flag) -{ - bool result; /* Bilan à retourner */ - fmt_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - LOCK_GOBJECT_EXTRA(extra); - - result = (extra->flags & flag); - - extra->flags &= ~flag; - - UNLOCK_GOBJECT_EXTRA(extra); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format à venir consulter. * -* flag = drapeau d'information à rechercher. * -* * -* Description : Détermine si un format possède un fanion particulier. * -* * -* Retour : Bilan de la détection. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_has_flag(const GBinFormat *format, FormatFlag flag) -{ - bool result; /* Bilan à retourner */ - fmt_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - LOCK_GOBJECT_EXTRA(extra); - - result = (extra->flags & flag); - - UNLOCK_GOBJECT_EXTRA(extra); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format à venir consulter. * -* * -* Description : Fournit les particularités du format. * -* * -* Retour : Somme de tous les fanions associés au format. * -* * -* Remarques : - * -* * -******************************************************************************/ - -FormatFlag g_binary_format_get_flags(const GBinFormat *format) -{ - FormatFlag result; /* Fanions à retourner */ - fmt_extra_data_t *extra; /* Données insérées à modifier */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - LOCK_GOBJECT_EXTRA(extra); - - result = (extra->flags & FFL_MASK); - - UNLOCK_GOBJECT_EXTRA(extra); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = description de l'exécutable à consulter. * -* * -* Description : Indique le boutisme employé par le format binaire analysé. * -* * -* Retour : Boutisme associé au format. * -* * -* Remarques : - * -* * -******************************************************************************/ - -SourceEndian g_binary_format_get_endianness(const GBinFormat *format) -{ - SourceEndian result; /* Boutisme à retourner */ - - result = G_BIN_FORMAT_GET_CLASS(format)->get_endian(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = description de l'exécutable à compléter. * -* pt = point de l'espace mémoire à considérer. * -* level = indication de priorité et d'origine de l'adresse. * -* * -* Description : Enregistre une adresse comme début d'une zone de code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, DisassPriorityLevel level) -{ - assert(level < DPL_COUNT); - - g_rw_lock_writer_lock(&format->pt_lock); - - if (format->pt_count[level] == format->pt_allocated[level]) - { - format->pt_allocated[level] += EXTRA_POINT_BLOCK; - - format->start_points[level] = realloc(format->start_points[level], - format->pt_allocated[level] * sizeof(virt_t)); - - } - - format->start_points[level][format->pt_count[level]++] = pt; - - g_rw_lock_writer_unlock(&format->pt_lock); - -} - - -/****************************************************************************** -* * -* Paramètres : proc = architecture concernée par la procédure. * -* pbuf = zone tampon à vider. * -* * -* Description : Charge les plages de couvertures depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_binary_format_load_start_points(GBinFormat *format, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - DisassPriorityLevel i; /* Boucle de parcours #1 */ - uleb128_t count; /* Quantité de points présents */ - size_t k; /* Boucle de parcours #2 */ - uleb128_t value; /* Valeur ULEB128 à charger */ - - result = true; - - g_rw_lock_writer_lock(&format->pt_lock); - - for (i = 0; i < DPL_COUNT && result; i++) - { - result = unpack_uleb128(&count, pbuf); - if (!result) break; - - format->pt_allocated[i] = count; - format->pt_count[i] = count; - - format->start_points[i] = calloc(format->pt_count[i], sizeof(virt_t)); - - for (k = 0; k < format->pt_count[i] && result; k++) - { - result = unpack_uleb128(&value, pbuf); - if (!result) break; - - format->start_points[i][k] = value; - - } - - } - - g_rw_lock_writer_unlock(&format->pt_lock); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = description de l'exécutable à consulter. * -* pbuf = zone tampon à remplir. * -* * -* Description : Sauvegarde les points de départ enregistrés pour un format. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_binary_format_store_start_points(GBinFormat *format, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - DisassPriorityLevel i; /* Boucle de parcours #1 */ - size_t count; /* Quantité de points présents */ - size_t k; /* Boucle de parcours #2 */ - - result = true; - - g_rw_lock_writer_lock(&format->pt_lock); - - for (i = 0; i < DPL_COUNT && result; i++) - { - count = format->pt_count[i]; - - result = pack_uleb128((uleb128_t []){ count }, pbuf); - - for (k = 0; k < count && result; k++) - result = pack_uleb128((uleb128_t []){ format->start_points[i][k] }, pbuf); - - } - - g_rw_lock_writer_unlock(&format->pt_lock); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = description de l'exécutable à consulter. * -* ctx = contexte de désassemblage à préparer. * -* status = barre de statut à tenir informée. * -* * -* Description : Intègre dans un contexte les informations tirées d'un format.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) -{ - g_preload_info_copy(format->info, G_PRELOAD_INFO(ctx)); - -} - - -/****************************************************************************** -* * -* Paramètres : format = description de l'exécutable à consulter. * -* ctx = contexte de désassemblage à préparer. * -* status = barre de statut à tenir informée. * -* * -* Description : Définit les points de départ d'un contexte de désassemblage. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_activate_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) -{ - DisassPriorityLevel i; /* Boucle de parcours #1 */ - size_t k; /* Boucle de parcours #2 */ - - g_rw_lock_reader_lock(&format->pt_lock); - - for (i = 0; i < DPL_COUNT; i++) - for (k = 0; k < format->pt_count[i]; k++) - g_proc_context_push_drop_point(ctx, i, format->start_points[i][k]); - - g_rw_lock_reader_unlock(&format->pt_lock); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* DECODAGE DE SYMBOLES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : format = format binaire à consulter pour l'opération. * -* * -* Description : Fournit le décodeur de symboles privilégié pour un format. * -* * -* Retour : Décodeur préféré ou NULL s'il n'est pas renseigné. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GCompDemangler *g_binary_format_get_demangler(const GBinFormat *format) -{ - GCompDemangler *result; /* Décodeur à retourner */ - - result = format->demangler; - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format binaire à consulter pour l'opération. * -* desc = chaîne de caractères à décoder. * -* * -* Description : Décode une chaîne de caractères donnée en type. * -* * -* Retour : Instance obtenue ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GDataType *g_binary_format_decode_type(const GBinFormat *format, const char *desc) -{ - GDataType *result; /* Construction à remonter */ - GCompDemangler *demangler; /* Accès plus lisible */ - - demangler = format->demangler; - - if (demangler != NULL) - result = g_compiler_demangler_decode_type(demangler, desc); - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format binaire à consulter pour l'opération. * -* desc = chaîne de caractères à décoder. * -* * -* Description : Décode une chaîne de caractères donnée en routine. * -* * -* Retour : Instance obtenue ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBinRoutine *g_binary_format_decode_routine(const GBinFormat *format, const char *desc) -{ - GBinRoutine *result; /* Construction à remonter */ - GCompDemangler *demangler; /* Accès plus lisible */ - - demangler = format->demangler; - - if (demangler != NULL) - result = g_compiler_demangler_decode_routine(demangler, desc); - else - result = NULL; - - if (result == NULL) - { - result = g_binary_routine_new(); - g_binary_routine_set_name(result, strdup(desc)); - } - - return result; - -} - - -/* ---------------------------------------------------------------------------------- */ -/* RASSEMBLEMENT ET GESTION DE SYMBOLES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : format = architecture à manipuler. * -* state = nouvel état de l'accès aux symboles. * -* * -* Description : Protège ou lève la protection de l'accès aux symboles. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_lock_unlock_symbols_rd(GBinFormat *format, bool state) -{ -#ifndef NDEBUG - gint test; /* Test de valeur courante */ -#endif - - if (state) - { - g_rw_lock_reader_lock(&format->syms_lock); -#ifndef NDEBUG - g_atomic_int_inc(&format->sym_locked); -#endif - } - else - { -#ifndef NDEBUG - test = g_atomic_int_add(&format->sym_locked, -1); - assert(test > 0); -#endif - g_rw_lock_reader_unlock(&format->syms_lock); - } - -} - - -/****************************************************************************** -* * -* Paramètres : format = architecture à manipuler. * -* state = nouvel état de l'accès aux symboles. * -* * -* Description : Protège ou lève la protection de l'accès aux symboles. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_lock_unlock_symbols_wr(GBinFormat *format, bool state) -{ - if (state) - { - g_rw_lock_writer_lock(&format->syms_lock); -#ifndef NDEBUG - g_atomic_int_set(&format->sym_locked, 1); -#endif - } - else - { -#ifndef NDEBUG - g_atomic_int_set(&format->sym_locked, 0); -#endif - g_rw_lock_writer_unlock(&format->syms_lock); - } - -} - - -/****************************************************************************** -* * -* Paramètres : format = architecture à consulter via la procédure. * -* * -* Description : Assure qu'un verrou est bien posé pour l'accès aux symboles. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ -#ifndef NDEBUG -void g_binary_format_check_for_symbols_lock(const GBinFormat *format) -{ - assert(g_atomic_int_get(&format->sym_locked) > 0); - -} -#endif - - -/****************************************************************************** -* * -* Paramètres : format = architecture à consulter via la procédure. * -* * -* Description : Fournit la marque de dernière modification des symboles. * -* * -* Retour : Marque de la dernière modification de la liste de symboles. * -* * -* Remarques : - * -* * -******************************************************************************/ - -unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *format) -{ - return format->sym_stamp; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format visé par la procédure. * -* * -* Description : Compte le nombre de symboles représentés. * -* * -* Retour : Nombre de symboles présents. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_binary_format_count_symbols(const GBinFormat *format) -{ - assert(g_atomic_int_get(&format->sym_locked) > 0); - - return format->sym_count; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format visé par la procédure. * -* index = indice du symbole visé. * -* * -* Description : Fournit un symbole lié à un format. * -* * -* Retour : Symbole conservé trouvé ou NULL si aucun. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBinSymbol *g_binary_format_get_symbol(const GBinFormat *format, size_t index) -{ - GBinSymbol *result; /* Symbole à retourner */ - - assert(g_atomic_int_get(&format->sym_locked) > 0); - - if (format->sym_count == 0) - result = NULL; - - else - { - assert(index < format->sym_count); - - result = format->symbols[index]; - assert(result != NULL); - - g_object_ref(G_OBJECT(result)); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à compléter. * -* symbol = symbole à ajouter à la liste. * -* * -* Description : Ajoute un symbole à la collection du format binaire. * -* * -* Retour : true si le symbole était bien localisé et a été inséré. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol) -{ - bool result; /* Statut d'ajout à retourner */ -#ifndef NDEBUG - const mrange_t *range; /* Couverture du symbole */ - const vmpa2t *addr; /* Emplacement du symbole */ -#endif - size_t index; /* Indice du point d'insertion */ - - /** - * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() - * fassent bien leur office, il faut que les symboles soient triés. - * - * Cependant, les localisations à satisfaire lors d'une recherche recontrent - * un problème si les positions physiques ne sont pas renseignées. En effet - * les adresses virtuelles en sont potentiellement décorrélées (c'est le cas - * avec le format ELF par exemple, où les zones en mémoire ne suivent pas le - * même ordre que les segments du binaire). - * - * Comme les comparaisons entre localisations se réalisent sur les éléments - * renseignés communs, à commencer par la position physique si c'est possible, - * une localisation s'appuyant uniquement sur une adresse virtuelle va être - * analysée suivant une liste non triée d'adresses virtuelles. - * - * On corrige donc le tir si besoin est en forçant la comparaison via les - * positions physiques. - */ - -#ifndef NDEBUG - range = g_binary_symbol_get_range(symbol); - addr = get_mrange_addr(range); - - assert(has_phys_addr(addr) || g_binary_symbol_get_status(symbol) == SSS_DYNAMIC); -#endif - - g_binary_format_lock_unlock_symbols_wr(format, true); - - /** - * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution - * amènent à la création d'un même symbole. - * - * Plutôt que de verrouiller la liste des symboles en amont (et donc assez longtemps) - * pour faire une vérification avant construction puis ajout, on préfère limiter - * l'état figé à cette seule fonction, quitte à annuler le travail fourni pour la - * construction du symbole dans les cas peu fréquents où le symbole était déjà en place. - */ - - result = bsearch_index(&symbol, format->symbols, format->sym_count, - sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); - - if (!result) - { - format->symbols = _qinsert(format->symbols, &format->sym_count, - sizeof(GBinSymbol *), &symbol, index); - - format->sym_stamp++; - result = true; - - } - else - g_object_unref(G_OBJECT(symbol)); - - g_binary_format_lock_unlock_symbols_wr(format, false); - - if (result) - g_signal_emit_by_name(format, "symbol-added", symbol); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à compléter. * -* symbols = ensemble de symboles à ajouter à la liste. * -* count = taille de cet ensemble. * -* * -* Description : Ajoute plusieurs symboles à la collection du format binaire. * -* * -* Retour : true si les symboles dûment localisés ont été insérés. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_t count) -{ - bool result; /* Statut d'ajout à retourner */ -#ifndef NDEBUG - phys_t last; /* Dernière position rencontrée*/ -#endif - size_t i; /* Boucle de parcours */ -#ifndef NDEBUG - const mrange_t *range; /* Couverture du symbole */ - const vmpa2t *addr; /* Emplacement du symbole */ -#endif - size_t index; /* Indice du point d'insertion */ - - /** - * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() - * fassent bien leur office, il faut que les symboles soient triés. - * - * Cependant, les localisations à satisfaire lors d'une recherche recontrent - * un problème si les positions physiques ne sont pas renseignées. En effet - * les adresses virtuelles en sont potentiellement décorrélées (c'est le cas - * avec le format ELF par exemple, où les zones en mémoire ne suivent pas le - * même ordre que les segments du binaire). - * - * Comme les comparaisons entre localisations se réalisent sur les éléments - * renseignés communs, à commencer par la position physique si c'est possible, - * une localisation s'appuyant uniquement sur une adresse virtuelle va être - * analysée suivant une liste non triée d'adresses virtuelles. - * - * On corrige donc le tir si besoin est en forçant la comparaison via les - * positions physiques. - */ - -#ifndef NDEBUG - last = VMPA_NO_PHYSICAL; - - for (i = 0; i < count; i++) - { - range = g_binary_symbol_get_range(symbols[i]); - addr = get_mrange_addr(range); - - assert(has_phys_addr(addr) || g_binary_symbol_get_status(symbols[i]) == SSS_DYNAMIC); - - if (has_phys_addr(addr)) - { - assert(last == VMPA_NO_PHYSICAL || last <= get_phy_addr(addr)); - last = get_phy_addr(addr); - } - - } -#endif - - g_binary_format_lock_unlock_symbols_wr(format, true); - - /** - * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution - * amènent à la création d'un même symbole. - * - * Plutôt que de verrouiller la liste des symboles en amont (et donc assez longtemps) - * pour faire une vérification avant construction puis ajout, on préfère limiter - * l'état figé à cette seule fonction, quitte à annuler le travail fourni pour la - * construction du symbole dans les cas peu fréquents où le symbole était déjà en place. - */ - - result = bsearch_index(&symbols[0], format->symbols, format->sym_count, - sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); - - if (!result) - { - for (i = 0; i < count; i++) - g_object_ref(G_OBJECT(symbols[i])); - - format->symbols = _qinsert_batch(format->symbols, &format->sym_count, - sizeof(GBinSymbol *), symbols, count, index); - - format->sym_stamp++; - result = true; - - } - - g_binary_format_lock_unlock_symbols_wr(format, false); - - if (result) - for (i = 0; i < count; i++) - g_signal_emit_by_name(format, "symbol-added", symbols[i]); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à compléter. * -* index = indice du symbole à retirer de la liste. * -* * -* Description : Retire un symbole de la collection du format binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void _g_binary_format_remove_symbol(GBinFormat *format, size_t index) -{ - assert(g_atomic_int_get(&format->sym_locked) == 1); - - assert(index < format->sym_count); - - g_object_unref(G_OBJECT(format->symbols[index])); - - if ((index + 1) < format->sym_count) - memmove(&format->symbols[index], &format->symbols[index + 1], - (format->sym_count - index - 1) * sizeof(GBinSymbol *)); - - format->symbols = realloc(format->symbols, --format->sym_count * sizeof(GBinSymbol *)); - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à compléter. * -* symbol = symbole à retirer de la liste. * -* * -* Description : Retire un symbole de la collection du format binaire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_remove_symbol(GBinFormat *format, GBinSymbol *symbol) -{ - bool found; /* Jeton de présence */ - size_t index; /* Indice du point de retrait */ - - g_object_ref(G_OBJECT(symbol)); - - g_binary_format_lock_unlock_symbols_wr(format, true); - - found = bsearch_index(&symbol, format->symbols, format->sym_count, - sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); - - if (found) - _g_binary_format_remove_symbol(format, index); - - g_binary_format_lock_unlock_symbols_wr(format, false); - - if (found) - g_signal_emit_by_name(format, "symbol-removed", symbol); - - g_object_unref(G_OBJECT(symbol)); - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* label = étiquette à retrouver lors des recherches. * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* * -* Description : Recherche le symbole correspondant à une étiquette. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label, GBinSymbol **symbol) -{ - bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours */ - char *cur_lbl; /* Etiquette courante */ - - result = false; - - g_binary_format_lock_symbols_rd(format); - - for (i = 0; i < format->sym_count && !result; i++) - { - cur_lbl = g_binary_symbol_get_label(format->symbols[i]); - if (cur_lbl == NULL) continue; - - if (strcmp(label, cur_lbl) == 0) - { - *symbol = format->symbols[i]; - g_object_ref(G_OBJECT(*symbol)); - - result = true; - - } - - free(cur_lbl); - - } - - g_binary_format_unlock_symbols_rd(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* addr = adresse à cibler lors des recherches. * -* fn = méthode de comparaison des symboles. * -* index = indice de l'éventuel symbole trouvé ou NULL. [OUT] * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* * -* Description : Recherche le symbole associé à une adresse. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t *addr, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) -{ - /** - * Pour ce qui est des justifications quant à la vérification suivante, - * se référer aux commentaires placés dans g_binary_format_add_symbol(). - */ - - assert(has_phys_addr(addr)); - - return __g_binary_format_find_symbol(format, addr, fn, index, symbol); - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* key = clef fournie pour distinguer les éléments. * -* fn = méthode de comparaison des symboles. * -* index = indice de l'éventuel symbole trouvé ou NULL. [OUT] * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* * -* Description : Recherche un symbole particulier. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool __g_binary_format_find_symbol(const GBinFormat *format, const void *key, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) -{ - bool result; /* Bilan à retourner */ - void *found; /* Résultat de recherches */ - - assert(g_atomic_int_get(&format->sym_locked) > 0); - - found = bsearch(key, format->symbols, format->sym_count, sizeof(GBinSymbol *), fn); - - if (found != NULL) - { - if (index != NULL) - *index = (GBinSymbol **)found - format->symbols; - - if (symbol != NULL) - { - *symbol = *(GBinSymbol **)found; - g_object_ref(G_OBJECT(*symbol)); - } - - result = true; - - } - - else - { - if (symbol != NULL) - *symbol = NULL; - - result = false; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* addr = adresse à cibler lors des recherches. * -* index = indice de l'éventuel symbole trouvé. [OUT] * -* * -* Description : Recherche l'indice du symbole correspondant à une adresse. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_find_symbol_index_at(GBinFormat *format, const vmpa2t *addr, size_t *index) -{ - bool result; /* Bilan à retourner */ - - int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) - { - const mrange_t *range; /* Espace mémoire parcouru */ - - range = g_binary_symbol_get_range(*sym); - - return cmp_vmpa(addr, get_mrange_addr(range)); - - } - - g_binary_format_lock_symbols_rd(format); - - result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, index, NULL); - - g_binary_format_unlock_symbols_rd(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* addr = adresse à cibler lors des recherches. * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* * -* Description : Recherche le symbole correspondant à une adresse. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_find_symbol_at(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) -{ - bool result; /* Bilan à retourner */ - - int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) - { - const mrange_t *range; /* Espace mémoire parcouru */ - - range = g_binary_symbol_get_range(*sym); - - return cmp_vmpa(addr, get_mrange_addr(range)); - - } - - g_binary_format_lock_symbols_rd(format); - - result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); - - g_binary_format_unlock_symbols_rd(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* addr = adresse à cibler lors des recherches. * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* * -* Description : Recherche le symbole contenant une adresse. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_find_symbol_for(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) -{ - bool result; /* Bilan à retourner */ - - int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) - { - const mrange_t *range; /* Espace mémoire parcouru */ - - range = g_binary_symbol_get_range(*sym); - - return cmp_mrange_with_vmpa(range, addr); - - } - - g_binary_format_lock_symbols_rd(format); - - result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); - - g_binary_format_unlock_symbols_rd(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* addr = adresse à cibler lors des recherches. * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* * -* Description : Recherche le symbole suivant celui lié à une adresse. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) -{ - bool result; /* Bilan à retourner */ - size_t index; /* Indice à considérer */ - - int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) - { - const mrange_t *range; /* Espace mémoire parcouru */ - - range = g_binary_symbol_get_range(*sym); - - return cmp_mrange_with_vmpa(range, addr); - - } - - g_binary_format_lock_symbols_rd(format); - - result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, &index, NULL); - - if (result && (index + 1) < format->sym_count) - { - *symbol = format->symbols[index + 1]; - g_object_ref(G_OBJECT(*symbol)); - - } - - else - { - *symbol = NULL; - result = false; - } - - g_binary_format_unlock_symbols_rd(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* range = zone à cibler lors des recherches. * -* index = indice de l'éventuel symbole trouvé. [OUT] * -* * -* Description : Recherche le premier symbole inclus dans une zone mémoire. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_find_first_symbol_inside(GBinFormat *format, const mrange_t *range, size_t *index) -{ - bool result; /* Bilan à retourner */ - const GBinSymbol *prev; /* Symbole précédent */ - const mrange_t *srange; /* Espace mémoire associé */ - int ret; /* Bilan de comparaison */ - - int find_symbol(const mrange_t *ref_range, const GBinSymbol **sym) - { - const mrange_t *sym_range; /* Espace mémoire parcouru */ - - int ret; - - sym_range = g_binary_symbol_get_range(*sym); - - ret = cmp_mrange_with_vmpa(ref_range, get_mrange_addr(sym_range)); - - ret *= -1; - - return ret; - - } - - g_rw_lock_reader_lock(&format->syms_lock); - - result = __g_binary_format_find_symbol(format, range, (__compar_fn_t)find_symbol, index, NULL); - - if (result) - while (*index > 0) - { - prev = format->symbols[*index - 1]; - srange = g_binary_symbol_get_range(prev); - - ret = cmp_mrange_with_vmpa(range, get_mrange_addr(srange)); - assert(ret <= 0); - - if (ret < 0) break; - else (*index)--; - - } - - g_rw_lock_reader_unlock(&format->syms_lock); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = informations chargées à consulter. * -* addr = adresse à cibler lors des recherches. * -* strict = indication de tolérance acceptée. * -* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * -* diff = décalage entre l'adresse et le symbole. [OUT] * -* * -* Description : Recherche le symbole correspondant à une adresse. * -* * -* Retour : true si l'opération a été un succès, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_resolve_symbol(GBinFormat *format, const vmpa2t *addr, bool strict, GBinSymbol **symbol, phys_t *diff) -{ - bool result; /* Bilan à retourner */ - const mrange_t *range; /* Espace mémoire parcouru */ - - if (strict) - result = g_binary_format_find_symbol_at(format, addr, symbol); - else - result = g_binary_format_find_symbol_for(format, addr, symbol); - - if (result) - { - range = g_binary_symbol_get_range(*symbol); - *diff = compute_vmpa_diff(get_mrange_addr(range), addr); - - assert(!strict || *diff == 0); - - } - - else - *diff = 0; - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* CONSERVATION DES SOUCIS DURANT LE CHARGEMENT */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : format = architecture à manipuler. * -* state = nouvel état de l'accès aux erreurs relevées. * -* * -* Description : Protège ou lève la protection de l'accès aux erreurs. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_lock_unlock_errors(GBinFormat *format, bool state) -{ - if (state) - { - g_mutex_lock(&format->error_mutex); -#ifndef NDEBUG - g_atomic_int_set(&format->error_locked, 1); -#endif - } - else - { -#ifndef NDEBUG - g_atomic_int_set(&format->error_locked, 0); -#endif - g_mutex_unlock(&format->error_mutex); - } - -} - - -/****************************************************************************** -* * -* Paramètres : format = architecture concernée par la procédure. * -* index = indice du problème visé. * -* type = type d'erreur retrouvée. * -* addr = localisation associée. * -* desc = éventuelle description humaine de description. * -* * -* Description : Etend la liste des soucis détectés avec de nouvelles infos. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_binary_format_add_error(GBinFormat *format, BinaryFormatError type, const vmpa2t *addr, const char *desc) -{ - fmt_error *error; /* Raccourci de confort */ - - g_binary_format_lock_errors(format); - - format->errors = realloc(format->errors, ++format->error_count * sizeof(fmt_error)); - - error = &format->errors[format->error_count - 1]; - - error->type = type; - - copy_vmpa(&error->addr, addr); - - if (desc != NULL) - error->desc = strdup(desc); - else - error->desc = NULL; - - g_binary_format_unlock_errors(format); - -} - - -/****************************************************************************** -* * -* Paramètres : format = architecture à consulter durant la procédure. * -* * -* Description : Indique le nombre d'erreurs relevées au niveau assembleur. * -* * -* Retour : Nombre d'erreurs en stock. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_binary_format_count_errors(GBinFormat *format) -{ - size_t result; /* Quantité à retourner */ - - assert(g_atomic_int_get(&format->error_locked) == 1); - - result = format->error_count; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = architecture concernée par la procédure. * -* index = indice du problème visé. * -* type = type d'erreur retrouvée. [OUT] * -* addr = localisation associée. [OUT] * -* desc = éventuelle description humaine de description. [OUT]* -* * -* Description : Fournit les éléments concernant un soucis détecté. * -* * -* Retour : Validité des informations renseignées. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_binary_format_get_error(GBinFormat *format, size_t index, BinaryFormatError *type, vmpa2t *addr, char **desc) -{ - bool result; /* Bilan à retourner */ - fmt_error *error; /* Raccourci de confort */ - - assert(g_atomic_int_get(&format->error_locked) == 1); - - result = (index < format->error_count); - - assert(result); - - if (result) - { - error = &format->errors[index]; - - *type = error->type; - - copy_vmpa(addr, &error->addr); - - if (error->desc != NULL) - *desc = strdup(error->desc); - else - *desc = NULL; - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format de binaire concerné par la procédure. * -* pbuf = zone tampon à vider. * -* * -* Description : Charge les erreurs de chargement depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_binary_format_load_errors(GBinFormat *format, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - uleb128_t value; /* Valeur ULEB128 à charger */ - size_t i; /* Boucle de parcours */ - fmt_error *error; /* Raccourci de confort */ - rle_string str; /* Chaîne à charger */ - - g_binary_format_lock_errors(format); - - result = unpack_uleb128(&value, pbuf); - if (!result) goto exit; - - format->error_count = value; - - format->errors = calloc(format->error_count, sizeof(fmt_error)); - - for (i = 0; i < format->error_count && result; i++) - { - error = &format->errors[i]; - - result = unpack_uleb128(&value, pbuf); - if (!result) break; - - error->type = value; - - result = unpack_vmpa(&error->addr, pbuf); - if (!result) break; - - setup_empty_rle_string(&str); - - result = unpack_rle_string(&str, pbuf); - if (!result) break; - - if (get_rle_string(&str) != NULL) - error->desc = strdup(get_rle_string(&str)); - - exit_rle_string(&str); - - } - - exit: - - g_binary_format_unlock_errors(format); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : format = format de binaire concerné par la procédure. * -* pbuf = zone tampon à remplir. * -* * -* Description : Sauvegarde les erreurs de chargement dans une mémoire tampon.* -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_binary_format_store_errors(GBinFormat *format, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - size_t i; /* Boucle de parcours */ - fmt_error *error; /* Raccourci de confort */ - rle_string str; /* Chaîne à conserver */ - - g_binary_format_lock_errors(format); - - result = pack_uleb128((uleb128_t []){ format->error_count }, pbuf); - - for (i = 0; i < format->error_count && result; i++) - { - error = &format->errors[i]; - - result = pack_uleb128((uleb128_t []){ error->type }, pbuf); - if (!result) break; - - result = pack_vmpa(&error->addr, pbuf); - if (!result) break; - - init_static_rle_string(&str, error->desc); - - result = pack_rle_string(&str, pbuf); - - exit_rle_string(&str); - - } - - g_binary_format_unlock_errors(format); - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : operand = élément GLib à constuire. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à lire. * -* * -* Description : Charge un format depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_binary_format_load(GBinFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - fmt_extra_data_t *extra; /* Données insérées à consulter*/ - uleb128_t value; /* Valeur ULEB128 à charger */ - rle_string str; /* Chaîne à charger */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - LOCK_GOBJECT_EXTRA(extra); - - result = unpack_uleb128(&value, pbuf); - - if (result) - extra->flags = value; - - UNLOCK_GOBJECT_EXTRA(extra); - - if (result) - result = g_binary_format_load_start_points(format, pbuf); - - if (result) - { - setup_empty_rle_string(&str); - - result = unpack_rle_string(&str, pbuf); - - if (result) - result = (get_rle_string(&str) != NULL); - - if (result) - format->demangler = get_compiler_demangler_for_key(get_rle_string(&str)); - - if (result) - result = (format->demangler != NULL); - - exit_rle_string(&str); - - } - - - - - - if (result) - result = g_binary_format_load_errors(format, pbuf); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = élément GLib à consulter. * -* storage = conservateur de données à manipuler ou NULL. * -* pbuf = zone tampon à remplir. * -* * -* Description : Sauvegarde un format dans une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_binary_format_store(GBinFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf) -{ - bool result; /* Bilan à retourner */ - fmt_extra_data_t *extra; /* Données insérées à consulter*/ - char *key; /* Désignation du décodeur */ - rle_string str; /* Chaîne à conserver */ - - extra = GET_BIN_FORMAT_EXTRA(format); - - LOCK_GOBJECT_EXTRA(extra); - - result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf); - - UNLOCK_GOBJECT_EXTRA(extra); - - if (result) - result = g_binary_format_store_start_points(format, pbuf); - - if (result) - { - key = g_compiler_demangler_get_key(format->demangler); - init_dynamic_rle_string(&str, key); - - result = pack_rle_string(&str, pbuf); - - exit_rle_string(&str); - - } - - - - - - - if (result) - result = g_binary_format_store_errors(format, pbuf); - - return result; - -} diff --git a/src/format/format.h b/src/format/format.h deleted file mode 100644 index f9aa430..0000000 --- a/src/format/format.h +++ /dev/null @@ -1,200 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * format.h - prototypes pour le support des différents formats binaires - * - * Copyright (C) 2009-2020 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see . - */ - - -#ifndef _FORMAT_FORMAT_H -#define _FORMAT_FORMAT_H - - -#include -#include -#include - - -#include "symbol.h" -#include "../analysis/content.h" -#include "../arch/context.h" -#include "../glibext/delayed.h" -#include "../glibext/notifier.h" - - - -/* Depuis ../mangling/demangler.h : Décodeur de désignations générique (instance) */ -typedef struct _GCompDemangler GCompDemangler; - -/* Indications supplémentaires liées aux formats */ -typedef enum _FormatFlag -{ - FFL_NONE = (0 << 0), /* Aucune propriété */ - FFL_RUN_IN_KERNEL_SPACE = (1 << 0), /* Exécution en espace noyau */ - - FFL_MASK = (1 << 1) - 1, /* Indication de nature */ - -} FormatFlag; - - -#define G_TYPE_BIN_FORMAT g_binary_format_get_type() -#define G_BIN_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BIN_FORMAT, GBinFormat)) -#define G_IS_BIN_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BIN_FORMAT)) -#define G_BIN_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BIN_FORMAT, GBinFormatClass)) -#define G_IS_BIN_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BIN_FORMAT)) -#define G_BIN_FORMAT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BIN_FORMAT, GBinFormatClass)) - - -/* Format binaire générique (instance) */ -typedef struct _GBinFormat GBinFormat; - -/* Format binaire générique (classe) */ -typedef struct _GBinFormatClass GBinFormatClass; - - -/* Indique le type défini pour un format binaire générique. */ -GType g_binary_format_get_type(void); - -/* Ajoute une information complémentaire à un format. */ -bool g_binary_format_set_flag(GBinFormat *, FormatFlag); - -/* Retire une information complémentaire à un format. */ -bool g_binary_format_unset_flag(GBinFormat *, FormatFlag); - -/* Détermine si un format possède un fanion particulier. */ -bool g_binary_format_has_flag(const GBinFormat *, FormatFlag); - -/* Fournit les particularités du format. */ -FormatFlag g_binary_format_get_flags(const GBinFormat *); - -/* Indique le boutisme employé par le format binaire analysé. */ -SourceEndian g_binary_format_get_endianness(const GBinFormat *); - -/* Enregistre une adresse comme début d'une zone de code. */ -void g_binary_format_register_code_point(GBinFormat *, virt_t, DisassPriorityLevel); - -/* Intègre dans un contexte les informations tirées d'un format. */ -void g_binary_format_preload_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); - -/* Définit les points de départ d'un contexte de désassemblage. */ -void g_binary_format_activate_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); - - - -/* ------------------------------ DECODAGE DE SYMBOLES ------------------------------ */ - - -/* Fournit le décodeur de symboles privilégié pour un format. */ -GCompDemangler *g_binary_format_get_demangler(const GBinFormat *); - - - -/* ---------------------- RASSEMBLEMENT ET GESTION DE SYMBOLES ---------------------- */ - - -/* Protège ou lève la protection de l'accès aux symboles. */ -void g_binary_format_lock_unlock_symbols_rd(GBinFormat *, bool); - -#define g_binary_format_lock_symbols_rd(f) g_binary_format_lock_unlock_symbols_rd(f, true) -#define g_binary_format_unlock_symbols_rd(f) g_binary_format_lock_unlock_symbols_rd(f, false) - -/* Protège ou lève la protection de l'accès aux symboles. */ -void g_binary_format_lock_unlock_symbols_wr(GBinFormat *, bool); - -#define g_binary_format_lock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, true) -#define g_binary_format_unlock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, false) - -/* Assure qu'un verrou est bien posé pour l'accès aux symboles. */ -#ifndef NDEBUG -void g_binary_format_check_for_symbols_lock(const GBinFormat *); -#endif - -/* Fournit la marque de dernière modification des symboles. */ -unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *); - -/* Compte le nombre de symboles représentés. */ -size_t g_binary_format_count_symbols(const GBinFormat *); - -/* Fournit un symbole lié à un format. */ -GBinSymbol *g_binary_format_get_symbol(const GBinFormat *, size_t); - -/* Ajoute un symbole à la collection du format binaire. */ -bool g_binary_format_add_symbol(GBinFormat *, GBinSymbol *); - -/* Ajoute plusieurs symboles à la collection du format binaire. */ -bool g_binary_format_add_symbols(GBinFormat *, GBinSymbol **, size_t); - -/* Retire un symbole de la collection du format binaire. */ -void g_binary_format_remove_symbol(GBinFormat *, GBinSymbol *); - -/* Recherche le symbole correspondant à une étiquette. */ -bool g_binary_format_find_symbol_by_label(GBinFormat *, const char *, GBinSymbol **); - -/* Recherche l'indice du symbole correspondant à une adresse. */ -bool g_binary_format_find_symbol_index_at(GBinFormat *, const vmpa2t *, size_t *); - -/* Recherche le symbole correspondant à une adresse. */ -bool g_binary_format_find_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); - -/* Recherche le symbole contenant une adresse. */ -bool g_binary_format_find_symbol_for(GBinFormat *, const vmpa2t *, GBinSymbol **); - -/* Recherche le symbole suivant celui lié à une adresse. */ -bool g_binary_format_find_next_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); - -/* Recherche le premier symbole inclus dans une zone mémoire. */ -bool g_binary_format_find_first_symbol_inside(GBinFormat *, const mrange_t *, size_t *); - -/* Recherche le symbole correspondant à une adresse. */ -bool g_binary_format_resolve_symbol(GBinFormat *, const vmpa2t *, bool, GBinSymbol **, phys_t *); - - - -/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ - - -/* Types d'erreurs détectées */ - -#define FMT_ERROR(idx) ((idx << 2) | (0 << 0)) - -typedef enum _BinaryFormatError -{ - BFE_SPECIFICATION = FMT_ERROR(0), /* Non respect des specs */ - BFE_STRUCTURE = FMT_ERROR(1) /* Code non reconnu */ - -} BinaryFormatError; - - -/* Protège ou lève la protection de l'accès aux erreurs. */ -void g_binary_format_lock_unlock_errors(GBinFormat *, bool); - -#define g_binary_format_lock_errors(f) g_binary_format_lock_unlock_errors(f, true) -#define g_binary_format_unlock_errors(f) g_binary_format_lock_unlock_errors(f, false) - -/* Etend la liste des soucis détectés avec de nouvelles infos. */ -void g_binary_format_add_error(GBinFormat *, BinaryFormatError, const vmpa2t *, const char *); - -/* Indique le nombre d'erreurs relevées au niveau assembleur. */ -size_t g_binary_format_count_errors(GBinFormat *); - -/* Fournit les éléments concernant un soucis détecté. */ -bool g_binary_format_get_error(GBinFormat *, size_t, BinaryFormatError *, vmpa2t *, char **); - - - -#endif /* _FORMAT_FORMAT_H */ diff --git a/src/format/program-int.h b/src/format/program-int.h new file mode 100644 index 0000000..f18bb24 --- /dev/null +++ b/src/format/program-int.h @@ -0,0 +1,160 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format-int.h - prototypes utiles aux formats binaires + * + * Copyright (C) 2009-2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#ifndef _FORMAT_FORMAT_INT_H +#define _FORMAT_FORMAT_INT_H + + +#include "format.h" + + +#include "known-int.h" +#include "preload.h" +#include "../glibext/objhole.h" +#include "../mangling/demangler.h" + + + +/* ------------------------ TRAITEMENT INDIVIDUEL DE FORMATS ------------------------ */ + + +/* Indique le boutisme employé par le format binaire analysé. */ +typedef SourceEndian (* format_get_endian_fc) (const GBinFormat *); + +/* Rythme des allocations pour les entrées de code */ +#define EXTRA_POINT_BLOCK 20 + + +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _fmt_extra_data_t +{ + FormatFlag flags; /* Informations complémentaires*/ + +} fmt_extra_data_t; + +/* Encapsulation avec un verrou d'accès */ +typedef union _fmt_obj_extra_t +{ + fmt_extra_data_t data; /* Données embarquées */ + lockable_obj_extra_t lockable; /* Gestion d'accès aux fanions */ + +} fmt_obj_extra_t; + + +/* Description d'une erreur */ +typedef struct _fmt_error +{ + BinaryFormatError type; /* Type d'erreur */ + + vmpa2t addr; /* Localisation du problème */ + char *desc; /* Description du soucis */ + +} fmt_error; + +/* Format binaire générique (instance) */ +struct _GBinFormat +{ + GKnownFormat parent; /* A laisser en premier */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + + /** + * L'inclusion des informations suivantes dépend de l'architecture. + * + * Si la structure GObject possède un trou, on remplit de préférence + * ce dernier. + */ + + fmt_obj_extra_t extra; /* Externalisation embarquée */ + +#endif + + virt_t *start_points[DPL_COUNT]; /* Départ de désassemblage */ + size_t pt_allocated[DPL_COUNT]; /* Taille d'inscription allouée*/ + size_t pt_count[DPL_COUNT]; /* Nombre de points enregistrés*/ + GRWLock pt_lock; /* Accès à la liste des points */ + + GPreloadInfo *info; /* Préchargements du format */ + + GCompDemangler *demangler; /* Décodage de noms privilégié */ + + GBinSymbol **symbols; /* Liste des symboles trouvés */ + size_t sym_count; /* Quantité de ces symboles */ + unsigned int sym_stamp; /* Marque de suivi des modifs */ + GRWLock syms_lock; /* Accès à la liste de symboles*/ +#ifndef NDEBUG + gint sym_locked; /* Statut d'accès à la liste */ +#endif + + fmt_error *errors; /* Liste d'erreurs rencontrées */ + size_t error_count; /* Taille de cette liste */ + GMutex error_mutex; /* Verrou pour l'accès */ +#ifndef NDEBUG + gint error_locked; /* Statut d'accès à la liste */ +#endif + +}; + +/* Format binaire générique (classe) */ +struct _GBinFormatClass +{ + GKnownFormatClass parent; /* A laisser en premier */ + + format_get_endian_fc get_endian; /* Boutisme employé */ + + /* Signaux */ + + void (* symbol_added) (GBinFormat *, GBinSymbol *); + void (* symbol_removed) (GBinFormat *, GBinSymbol *); + +}; + + +/** + * Accès aux informations éventuellement déportées. + */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + +# define GET_BIN_FORMAT_EXTRA(fmt) (fmt_extra_data_t *)&fmt->extra + +#else + +# define GET_BIN_FORMAT_EXTRA(fmt) GET_GOBJECT_EXTRA(G_OBJECT(fmt), fmt_extra_data_t) + +#endif + + + +/* ------------------------------ DECODAGE DE SYMBOLES ------------------------------ */ + + +/* Décode une chaîne de caractères donnée en type. */ +GDataType *g_binary_format_decode_type(const GBinFormat *, const char *); + +/* Décode une chaîne de caractères donnée en routine. */ +GBinRoutine *g_binary_format_decode_routine(const GBinFormat *, const char *); + + + +#endif /* _FORMAT_FORMAT_INT_H */ diff --git a/src/format/program.c b/src/format/program.c new file mode 100644 index 0000000..d126236 --- /dev/null +++ b/src/format/program.c @@ -0,0 +1,1920 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.c - support des différents formats binaires + * + * Copyright (C) 2009-2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#include "format.h" + + +#include +#include +#include + + +#include "format-int.h" +#include "preload.h" +#include "../arch/processor.h" +#include "../common/sort.h" +#include "../core/demanglers.h" +#include "../plugins/pglist.h" + + + +/* Initialise la classe des formats binaires génériques. */ +static void g_binary_format_class_init(GBinFormatClass *); + +/* Initialise une instance de format binaire générique. */ +static void g_binary_format_init(GBinFormat *); + +/* Supprime toutes les références externes. */ +static void g_binary_format_dispose(GBinFormat *); + +/* Procède à la libération totale de la mémoire. */ +static void g_binary_format_finalize(GBinFormat *); + +/* Charge les plages de couvertures depuis une mémoire tampon. */ +static bool g_binary_format_load_start_points(GBinFormat *, packed_buffer_t *); + +/* Sauvegarde les points de départ enregistrés pour un format. */ +static bool g_binary_format_store_start_points(GBinFormat *, packed_buffer_t *); + + + +/* ---------------------- RASSEMBLEMENT ET GESTION DE SYMBOLES ---------------------- */ + + +/* Retire un symbole de la collection du format binaire. */ +static void _g_binary_format_remove_symbol(GBinFormat *, size_t); + +/* Recherche le symbole associé à une adresse. */ +static bool _g_binary_format_find_symbol(const GBinFormat *, const vmpa2t *, __compar_fn_t, size_t *, GBinSymbol **); + +/* Recherche un symbole particulier. */ +static bool __g_binary_format_find_symbol(const GBinFormat *, const void *, __compar_fn_t, size_t *, GBinSymbol **); + + + +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ + + +/* Charge les erreurs de chargement depuis une mémoire tampon. */ +static bool g_binary_format_load_errors(GBinFormat *, packed_buffer_t *); + +/* Sauvegarde les erreurs de chargement dans une mémoire tampon. */ +static bool g_binary_format_store_errors(GBinFormat *, packed_buffer_t *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Charge un format depuis une mémoire tampon. */ +static bool g_binary_format_load(GBinFormat *, GObjectStorage *, packed_buffer_t *); + +/* Sauvegarde un format dans une mémoire tampon. */ +static bool g_binary_format_store(GBinFormat *, GObjectStorage *, packed_buffer_t *); + + + + + +/* Indique le type défini pour un format binaire générique. */ +G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_KNOWN_FORMAT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des formats binaires génériques. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_format_class_init(GBinFormatClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GKnownFormatClass *known; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_format_dispose; + object->finalize = (GObjectFinalizeFunc)g_binary_format_finalize; + + known = G_KNOWN_FORMAT_CLASS(klass); + + known->load = (load_known_fc)g_binary_format_load; + known->store = (load_known_fc)g_binary_format_store; + + g_signal_new("symbol-added", + G_TYPE_BIN_FORMAT, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBinFormatClass, symbol_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + g_signal_new("symbol-removed", + G_TYPE_BIN_FORMAT, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GBinFormatClass, symbol_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance à initialiser. * +* * +* Description : Initialise une instance de format binaire générique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_format_init(GBinFormat *format) +{ + fmt_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + INIT_GOBJECT_EXTRA_LOCK(extra); + + g_rw_lock_init(&format->pt_lock); + + format->info = g_preload_info_new(); + + format->demangler = NULL; + + g_rw_lock_init(&format->syms_lock); +#ifndef NDEBUG + g_atomic_int_set(&format->sym_locked, 0); +#endif + + format->errors = NULL; + format->error_count = 0; + g_mutex_init(&format->error_mutex); +#ifndef NDEBUG + g_atomic_int_set(&format->error_locked, 0); +#endif + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_format_dispose(GBinFormat *format) +{ + size_t i; /* Boucle de parcours */ + + g_rw_lock_clear(&format->pt_lock); + + g_clear_object(&format->info); + + g_clear_object(&format->demangler); + + for (i = 0; i < format->sym_count; i++) + g_clear_object(&format->symbols[i]); + + g_rw_lock_clear(&format->syms_lock); + + g_mutex_clear(&format->error_mutex); + + G_OBJECT_CLASS(g_binary_format_parent_class)->dispose(G_OBJECT(format)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_binary_format_finalize(GBinFormat *format) +{ + DisassPriorityLevel i; /* Boucle de parcours #1 */ + size_t k; /* Boucle de parcours #2 */ + + for (i = 0; i < DPL_COUNT; i++) + if (format->start_points[i] != NULL) + free(format->start_points[i]); + + if (format->symbols != NULL) + free(format->symbols); + + if (format->errors != NULL) + { + for (k = 0; k < format->error_count; k++) + if (format->errors[k].desc != NULL) + free(format->errors[k].desc); + + free(format->errors); + + } + + G_OBJECT_CLASS(g_binary_format_parent_class)->finalize(G_OBJECT(format)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = format à venir modifier. * +* flag = drapeau d'information complémentaire à planter. * +* * +* Description : Ajoute une information complémentaire à un format. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_set_flag(GBinFormat *format, FormatFlag flag) +{ + bool result; /* Bilan à retourner */ + fmt_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + LOCK_GOBJECT_EXTRA(extra); + + result = !(extra->flags & flag); + + extra->flags |= flag; + + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format à venir modifier. * +* flag = drapeau d'information complémentaire à planter. * +* * +* Description : Retire une information complémentaire à un format. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_unset_flag(GBinFormat *format, FormatFlag flag) +{ + bool result; /* Bilan à retourner */ + fmt_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + LOCK_GOBJECT_EXTRA(extra); + + result = (extra->flags & flag); + + extra->flags &= ~flag; + + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format à venir consulter. * +* flag = drapeau d'information à rechercher. * +* * +* Description : Détermine si un format possède un fanion particulier. * +* * +* Retour : Bilan de la détection. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_has_flag(const GBinFormat *format, FormatFlag flag) +{ + bool result; /* Bilan à retourner */ + fmt_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + LOCK_GOBJECT_EXTRA(extra); + + result = (extra->flags & flag); + + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format à venir consulter. * +* * +* Description : Fournit les particularités du format. * +* * +* Retour : Somme de tous les fanions associés au format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +FormatFlag g_binary_format_get_flags(const GBinFormat *format) +{ + FormatFlag result; /* Fanions à retourner */ + fmt_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + LOCK_GOBJECT_EXTRA(extra); + + result = (extra->flags & FFL_MASK); + + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* * +* Description : Indique le boutisme employé par le format binaire analysé. * +* * +* Retour : Boutisme associé au format. * +* * +* Remarques : - * +* * +******************************************************************************/ + +SourceEndian g_binary_format_get_endianness(const GBinFormat *format) +{ + SourceEndian result; /* Boutisme à retourner */ + + result = G_BIN_FORMAT_GET_CLASS(format)->get_endian(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à compléter. * +* pt = point de l'espace mémoire à considérer. * +* level = indication de priorité et d'origine de l'adresse. * +* * +* Description : Enregistre une adresse comme début d'une zone de code. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_register_code_point(GBinFormat *format, virt_t pt, DisassPriorityLevel level) +{ + assert(level < DPL_COUNT); + + g_rw_lock_writer_lock(&format->pt_lock); + + if (format->pt_count[level] == format->pt_allocated[level]) + { + format->pt_allocated[level] += EXTRA_POINT_BLOCK; + + format->start_points[level] = realloc(format->start_points[level], + format->pt_allocated[level] * sizeof(virt_t)); + + } + + format->start_points[level][format->pt_count[level]++] = pt; + + g_rw_lock_writer_unlock(&format->pt_lock); + +} + + +/****************************************************************************** +* * +* Paramètres : proc = architecture concernée par la procédure. * +* pbuf = zone tampon à vider. * +* * +* Description : Charge les plages de couvertures depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_format_load_start_points(GBinFormat *format, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + DisassPriorityLevel i; /* Boucle de parcours #1 */ + uleb128_t count; /* Quantité de points présents */ + size_t k; /* Boucle de parcours #2 */ + uleb128_t value; /* Valeur ULEB128 à charger */ + + result = true; + + g_rw_lock_writer_lock(&format->pt_lock); + + for (i = 0; i < DPL_COUNT && result; i++) + { + result = unpack_uleb128(&count, pbuf); + if (!result) break; + + format->pt_allocated[i] = count; + format->pt_count[i] = count; + + format->start_points[i] = calloc(format->pt_count[i], sizeof(virt_t)); + + for (k = 0; k < format->pt_count[i] && result; k++) + { + result = unpack_uleb128(&value, pbuf); + if (!result) break; + + format->start_points[i][k] = value; + + } + + } + + g_rw_lock_writer_unlock(&format->pt_lock); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* pbuf = zone tampon à remplir. * +* * +* Description : Sauvegarde les points de départ enregistrés pour un format. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_format_store_start_points(GBinFormat *format, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + DisassPriorityLevel i; /* Boucle de parcours #1 */ + size_t count; /* Quantité de points présents */ + size_t k; /* Boucle de parcours #2 */ + + result = true; + + g_rw_lock_writer_lock(&format->pt_lock); + + for (i = 0; i < DPL_COUNT && result; i++) + { + count = format->pt_count[i]; + + result = pack_uleb128((uleb128_t []){ count }, pbuf); + + for (k = 0; k < count && result; k++) + result = pack_uleb128((uleb128_t []){ format->start_points[i][k] }, pbuf); + + } + + g_rw_lock_writer_unlock(&format->pt_lock); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* ctx = contexte de désassemblage à préparer. * +* status = barre de statut à tenir informée. * +* * +* Description : Intègre dans un contexte les informations tirées d'un format.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_preload_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) +{ + g_preload_info_copy(format->info, G_PRELOAD_INFO(ctx)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = description de l'exécutable à consulter. * +* ctx = contexte de désassemblage à préparer. * +* status = barre de statut à tenir informée. * +* * +* Description : Définit les points de départ d'un contexte de désassemblage. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_activate_disassembling_context(GBinFormat *format, GProcContext *ctx, GtkStatusStack *status) +{ + DisassPriorityLevel i; /* Boucle de parcours #1 */ + size_t k; /* Boucle de parcours #2 */ + + g_rw_lock_reader_lock(&format->pt_lock); + + for (i = 0; i < DPL_COUNT; i++) + for (k = 0; k < format->pt_count[i]; k++) + g_proc_context_push_drop_point(ctx, i, format->start_points[i][k]); + + g_rw_lock_reader_unlock(&format->pt_lock); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* DECODAGE DE SYMBOLES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = format binaire à consulter pour l'opération. * +* * +* Description : Fournit le décodeur de symboles privilégié pour un format. * +* * +* Retour : Décodeur préféré ou NULL s'il n'est pas renseigné. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GCompDemangler *g_binary_format_get_demangler(const GBinFormat *format) +{ + GCompDemangler *result; /* Décodeur à retourner */ + + result = format->demangler; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format binaire à consulter pour l'opération. * +* desc = chaîne de caractères à décoder. * +* * +* Description : Décode une chaîne de caractères donnée en type. * +* * +* Retour : Instance obtenue ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDataType *g_binary_format_decode_type(const GBinFormat *format, const char *desc) +{ + GDataType *result; /* Construction à remonter */ + GCompDemangler *demangler; /* Accès plus lisible */ + + demangler = format->demangler; + + if (demangler != NULL) + result = g_compiler_demangler_decode_type(demangler, desc); + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format binaire à consulter pour l'opération. * +* desc = chaîne de caractères à décoder. * +* * +* Description : Décode une chaîne de caractères donnée en routine. * +* * +* Retour : Instance obtenue ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinRoutine *g_binary_format_decode_routine(const GBinFormat *format, const char *desc) +{ + GBinRoutine *result; /* Construction à remonter */ + GCompDemangler *demangler; /* Accès plus lisible */ + + demangler = format->demangler; + + if (demangler != NULL) + result = g_compiler_demangler_decode_routine(demangler, desc); + else + result = NULL; + + if (result == NULL) + { + result = g_binary_routine_new(); + g_binary_routine_set_name(result, strdup(desc)); + } + + return result; + +} + + +/* ---------------------------------------------------------------------------------- */ +/* RASSEMBLEMENT ET GESTION DE SYMBOLES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = architecture à manipuler. * +* state = nouvel état de l'accès aux symboles. * +* * +* Description : Protège ou lève la protection de l'accès aux symboles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_lock_unlock_symbols_rd(GBinFormat *format, bool state) +{ +#ifndef NDEBUG + gint test; /* Test de valeur courante */ +#endif + + if (state) + { + g_rw_lock_reader_lock(&format->syms_lock); +#ifndef NDEBUG + g_atomic_int_inc(&format->sym_locked); +#endif + } + else + { +#ifndef NDEBUG + test = g_atomic_int_add(&format->sym_locked, -1); + assert(test > 0); +#endif + g_rw_lock_reader_unlock(&format->syms_lock); + } + +} + + +/****************************************************************************** +* * +* Paramètres : format = architecture à manipuler. * +* state = nouvel état de l'accès aux symboles. * +* * +* Description : Protège ou lève la protection de l'accès aux symboles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_lock_unlock_symbols_wr(GBinFormat *format, bool state) +{ + if (state) + { + g_rw_lock_writer_lock(&format->syms_lock); +#ifndef NDEBUG + g_atomic_int_set(&format->sym_locked, 1); +#endif + } + else + { +#ifndef NDEBUG + g_atomic_int_set(&format->sym_locked, 0); +#endif + g_rw_lock_writer_unlock(&format->syms_lock); + } + +} + + +/****************************************************************************** +* * +* Paramètres : format = architecture à consulter via la procédure. * +* * +* Description : Assure qu'un verrou est bien posé pour l'accès aux symboles. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ +#ifndef NDEBUG +void g_binary_format_check_for_symbols_lock(const GBinFormat *format) +{ + assert(g_atomic_int_get(&format->sym_locked) > 0); + +} +#endif + + +/****************************************************************************** +* * +* Paramètres : format = architecture à consulter via la procédure. * +* * +* Description : Fournit la marque de dernière modification des symboles. * +* * +* Retour : Marque de la dernière modification de la liste de symboles. * +* * +* Remarques : - * +* * +******************************************************************************/ + +unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *format) +{ + return format->sym_stamp; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format visé par la procédure. * +* * +* Description : Compte le nombre de symboles représentés. * +* * +* Retour : Nombre de symboles présents. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_binary_format_count_symbols(const GBinFormat *format) +{ + assert(g_atomic_int_get(&format->sym_locked) > 0); + + return format->sym_count; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format visé par la procédure. * +* index = indice du symbole visé. * +* * +* Description : Fournit un symbole lié à un format. * +* * +* Retour : Symbole conservé trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinSymbol *g_binary_format_get_symbol(const GBinFormat *format, size_t index) +{ + GBinSymbol *result; /* Symbole à retourner */ + + assert(g_atomic_int_get(&format->sym_locked) > 0); + + if (format->sym_count == 0) + result = NULL; + + else + { + assert(index < format->sym_count); + + result = format->symbols[index]; + assert(result != NULL); + + g_object_ref(G_OBJECT(result)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à compléter. * +* symbol = symbole à ajouter à la liste. * +* * +* Description : Ajoute un symbole à la collection du format binaire. * +* * +* Retour : true si le symbole était bien localisé et a été inséré. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol) +{ + bool result; /* Statut d'ajout à retourner */ +#ifndef NDEBUG + const mrange_t *range; /* Couverture du symbole */ + const vmpa2t *addr; /* Emplacement du symbole */ +#endif + size_t index; /* Indice du point d'insertion */ + + /** + * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() + * fassent bien leur office, il faut que les symboles soient triés. + * + * Cependant, les localisations à satisfaire lors d'une recherche recontrent + * un problème si les positions physiques ne sont pas renseignées. En effet + * les adresses virtuelles en sont potentiellement décorrélées (c'est le cas + * avec le format ELF par exemple, où les zones en mémoire ne suivent pas le + * même ordre que les segments du binaire). + * + * Comme les comparaisons entre localisations se réalisent sur les éléments + * renseignés communs, à commencer par la position physique si c'est possible, + * une localisation s'appuyant uniquement sur une adresse virtuelle va être + * analysée suivant une liste non triée d'adresses virtuelles. + * + * On corrige donc le tir si besoin est en forçant la comparaison via les + * positions physiques. + */ + +#ifndef NDEBUG + range = g_binary_symbol_get_range(symbol); + addr = get_mrange_addr(range); + + assert(has_phys_addr(addr) || g_binary_symbol_get_status(symbol) == SSS_DYNAMIC); +#endif + + g_binary_format_lock_unlock_symbols_wr(format, true); + + /** + * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution + * amènent à la création d'un même symbole. + * + * Plutôt que de verrouiller la liste des symboles en amont (et donc assez longtemps) + * pour faire une vérification avant construction puis ajout, on préfère limiter + * l'état figé à cette seule fonction, quitte à annuler le travail fourni pour la + * construction du symbole dans les cas peu fréquents où le symbole était déjà en place. + */ + + result = bsearch_index(&symbol, format->symbols, format->sym_count, + sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); + + if (!result) + { + format->symbols = _qinsert(format->symbols, &format->sym_count, + sizeof(GBinSymbol *), &symbol, index); + + format->sym_stamp++; + result = true; + + } + else + g_object_unref(G_OBJECT(symbol)); + + g_binary_format_lock_unlock_symbols_wr(format, false); + + if (result) + g_signal_emit_by_name(format, "symbol-added", symbol); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à compléter. * +* symbols = ensemble de symboles à ajouter à la liste. * +* count = taille de cet ensemble. * +* * +* Description : Ajoute plusieurs symboles à la collection du format binaire. * +* * +* Retour : true si les symboles dûment localisés ont été insérés. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_t count) +{ + bool result; /* Statut d'ajout à retourner */ +#ifndef NDEBUG + phys_t last; /* Dernière position rencontrée*/ +#endif + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + const mrange_t *range; /* Couverture du symbole */ + const vmpa2t *addr; /* Emplacement du symbole */ +#endif + size_t index; /* Indice du point d'insertion */ + + /** + * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() + * fassent bien leur office, il faut que les symboles soient triés. + * + * Cependant, les localisations à satisfaire lors d'une recherche recontrent + * un problème si les positions physiques ne sont pas renseignées. En effet + * les adresses virtuelles en sont potentiellement décorrélées (c'est le cas + * avec le format ELF par exemple, où les zones en mémoire ne suivent pas le + * même ordre que les segments du binaire). + * + * Comme les comparaisons entre localisations se réalisent sur les éléments + * renseignés communs, à commencer par la position physique si c'est possible, + * une localisation s'appuyant uniquement sur une adresse virtuelle va être + * analysée suivant une liste non triée d'adresses virtuelles. + * + * On corrige donc le tir si besoin est en forçant la comparaison via les + * positions physiques. + */ + +#ifndef NDEBUG + last = VMPA_NO_PHYSICAL; + + for (i = 0; i < count; i++) + { + range = g_binary_symbol_get_range(symbols[i]); + addr = get_mrange_addr(range); + + assert(has_phys_addr(addr) || g_binary_symbol_get_status(symbols[i]) == SSS_DYNAMIC); + + if (has_phys_addr(addr)) + { + assert(last == VMPA_NO_PHYSICAL || last <= get_phy_addr(addr)); + last = get_phy_addr(addr); + } + + } +#endif + + g_binary_format_lock_unlock_symbols_wr(format, true); + + /** + * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution + * amènent à la création d'un même symbole. + * + * Plutôt que de verrouiller la liste des symboles en amont (et donc assez longtemps) + * pour faire une vérification avant construction puis ajout, on préfère limiter + * l'état figé à cette seule fonction, quitte à annuler le travail fourni pour la + * construction du symbole dans les cas peu fréquents où le symbole était déjà en place. + */ + + result = bsearch_index(&symbols[0], format->symbols, format->sym_count, + sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); + + if (!result) + { + for (i = 0; i < count; i++) + g_object_ref(G_OBJECT(symbols[i])); + + format->symbols = _qinsert_batch(format->symbols, &format->sym_count, + sizeof(GBinSymbol *), symbols, count, index); + + format->sym_stamp++; + result = true; + + } + + g_binary_format_lock_unlock_symbols_wr(format, false); + + if (result) + for (i = 0; i < count; i++) + g_signal_emit_by_name(format, "symbol-added", symbols[i]); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à compléter. * +* index = indice du symbole à retirer de la liste. * +* * +* Description : Retire un symbole de la collection du format binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void _g_binary_format_remove_symbol(GBinFormat *format, size_t index) +{ + assert(g_atomic_int_get(&format->sym_locked) == 1); + + assert(index < format->sym_count); + + g_object_unref(G_OBJECT(format->symbols[index])); + + if ((index + 1) < format->sym_count) + memmove(&format->symbols[index], &format->symbols[index + 1], + (format->sym_count - index - 1) * sizeof(GBinSymbol *)); + + format->symbols = realloc(format->symbols, --format->sym_count * sizeof(GBinSymbol *)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à compléter. * +* symbol = symbole à retirer de la liste. * +* * +* Description : Retire un symbole de la collection du format binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_remove_symbol(GBinFormat *format, GBinSymbol *symbol) +{ + bool found; /* Jeton de présence */ + size_t index; /* Indice du point de retrait */ + + g_object_ref(G_OBJECT(symbol)); + + g_binary_format_lock_unlock_symbols_wr(format, true); + + found = bsearch_index(&symbol, format->symbols, format->sym_count, + sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); + + if (found) + _g_binary_format_remove_symbol(format, index); + + g_binary_format_lock_unlock_symbols_wr(format, false); + + if (found) + g_signal_emit_by_name(format, "symbol-removed", symbol); + + g_object_unref(G_OBJECT(symbol)); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* label = étiquette à retrouver lors des recherches. * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche le symbole correspondant à une étiquette. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_symbol_by_label(GBinFormat *format, const char *label, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + char *cur_lbl; /* Etiquette courante */ + + result = false; + + g_binary_format_lock_symbols_rd(format); + + for (i = 0; i < format->sym_count && !result; i++) + { + cur_lbl = g_binary_symbol_get_label(format->symbols[i]); + if (cur_lbl == NULL) continue; + + if (strcmp(label, cur_lbl) == 0) + { + *symbol = format->symbols[i]; + g_object_ref(G_OBJECT(*symbol)); + + result = true; + + } + + free(cur_lbl); + + } + + g_binary_format_unlock_symbols_rd(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* fn = méthode de comparaison des symboles. * +* index = indice de l'éventuel symbole trouvé ou NULL. [OUT] * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche le symbole associé à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_binary_format_find_symbol(const GBinFormat *format, const vmpa2t *addr, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) +{ + /** + * Pour ce qui est des justifications quant à la vérification suivante, + * se référer aux commentaires placés dans g_binary_format_add_symbol(). + */ + + assert(has_phys_addr(addr)); + + return __g_binary_format_find_symbol(format, addr, fn, index, symbol); + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* key = clef fournie pour distinguer les éléments. * +* fn = méthode de comparaison des symboles. * +* index = indice de l'éventuel symbole trouvé ou NULL. [OUT] * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche un symbole particulier. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool __g_binary_format_find_symbol(const GBinFormat *format, const void *key, __compar_fn_t fn, size_t *index, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + void *found; /* Résultat de recherches */ + + assert(g_atomic_int_get(&format->sym_locked) > 0); + + found = bsearch(key, format->symbols, format->sym_count, sizeof(GBinSymbol *), fn); + + if (found != NULL) + { + if (index != NULL) + *index = (GBinSymbol **)found - format->symbols; + + if (symbol != NULL) + { + *symbol = *(GBinSymbol **)found; + g_object_ref(G_OBJECT(*symbol)); + } + + result = true; + + } + + else + { + if (symbol != NULL) + *symbol = NULL; + + result = false; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* index = indice de l'éventuel symbole trouvé. [OUT] * +* * +* Description : Recherche l'indice du symbole correspondant à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_symbol_index_at(GBinFormat *format, const vmpa2t *addr, size_t *index) +{ + bool result; /* Bilan à retourner */ + + int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) + { + const mrange_t *range; /* Espace mémoire parcouru */ + + range = g_binary_symbol_get_range(*sym); + + return cmp_vmpa(addr, get_mrange_addr(range)); + + } + + g_binary_format_lock_symbols_rd(format); + + result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, index, NULL); + + g_binary_format_unlock_symbols_rd(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche le symbole correspondant à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_symbol_at(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + + int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) + { + const mrange_t *range; /* Espace mémoire parcouru */ + + range = g_binary_symbol_get_range(*sym); + + return cmp_vmpa(addr, get_mrange_addr(range)); + + } + + g_binary_format_lock_symbols_rd(format); + + result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); + + g_binary_format_unlock_symbols_rd(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche le symbole contenant une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_symbol_for(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + + int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) + { + const mrange_t *range; /* Espace mémoire parcouru */ + + range = g_binary_symbol_get_range(*sym); + + return cmp_mrange_with_vmpa(range, addr); + + } + + g_binary_format_lock_symbols_rd(format); + + result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, NULL, symbol); + + g_binary_format_unlock_symbols_rd(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* * +* Description : Recherche le symbole suivant celui lié à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_next_symbol_at(GBinFormat *format, const vmpa2t *addr, GBinSymbol **symbol) +{ + bool result; /* Bilan à retourner */ + size_t index; /* Indice à considérer */ + + int find_symbol(const vmpa2t *addr, const GBinSymbol **sym) + { + const mrange_t *range; /* Espace mémoire parcouru */ + + range = g_binary_symbol_get_range(*sym); + + return cmp_mrange_with_vmpa(range, addr); + + } + + g_binary_format_lock_symbols_rd(format); + + result = _g_binary_format_find_symbol(format, addr, (__compar_fn_t)find_symbol, &index, NULL); + + if (result && (index + 1) < format->sym_count) + { + *symbol = format->symbols[index + 1]; + g_object_ref(G_OBJECT(*symbol)); + + } + + else + { + *symbol = NULL; + result = false; + } + + g_binary_format_unlock_symbols_rd(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* range = zone à cibler lors des recherches. * +* index = indice de l'éventuel symbole trouvé. [OUT] * +* * +* Description : Recherche le premier symbole inclus dans une zone mémoire. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_find_first_symbol_inside(GBinFormat *format, const mrange_t *range, size_t *index) +{ + bool result; /* Bilan à retourner */ + const GBinSymbol *prev; /* Symbole précédent */ + const mrange_t *srange; /* Espace mémoire associé */ + int ret; /* Bilan de comparaison */ + + int find_symbol(const mrange_t *ref_range, const GBinSymbol **sym) + { + const mrange_t *sym_range; /* Espace mémoire parcouru */ + + int ret; + + sym_range = g_binary_symbol_get_range(*sym); + + ret = cmp_mrange_with_vmpa(ref_range, get_mrange_addr(sym_range)); + + ret *= -1; + + return ret; + + } + + g_rw_lock_reader_lock(&format->syms_lock); + + result = __g_binary_format_find_symbol(format, range, (__compar_fn_t)find_symbol, index, NULL); + + if (result) + while (*index > 0) + { + prev = format->symbols[*index - 1]; + srange = g_binary_symbol_get_range(prev); + + ret = cmp_mrange_with_vmpa(range, get_mrange_addr(srange)); + assert(ret <= 0); + + if (ret < 0) break; + else (*index)--; + + } + + g_rw_lock_reader_unlock(&format->syms_lock); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = informations chargées à consulter. * +* addr = adresse à cibler lors des recherches. * +* strict = indication de tolérance acceptée. * +* symbol = éventuel symbole trouvé à déréfenrencer. [OUT] * +* diff = décalage entre l'adresse et le symbole. [OUT] * +* * +* Description : Recherche le symbole correspondant à une adresse. * +* * +* Retour : true si l'opération a été un succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_resolve_symbol(GBinFormat *format, const vmpa2t *addr, bool strict, GBinSymbol **symbol, phys_t *diff) +{ + bool result; /* Bilan à retourner */ + const mrange_t *range; /* Espace mémoire parcouru */ + + if (strict) + result = g_binary_format_find_symbol_at(format, addr, symbol); + else + result = g_binary_format_find_symbol_for(format, addr, symbol); + + if (result) + { + range = g_binary_symbol_get_range(*symbol); + *diff = compute_vmpa_diff(get_mrange_addr(range), addr); + + assert(!strict || *diff == 0); + + } + + else + *diff = 0; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONSERVATION DES SOUCIS DURANT LE CHARGEMENT */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : format = architecture à manipuler. * +* state = nouvel état de l'accès aux erreurs relevées. * +* * +* Description : Protège ou lève la protection de l'accès aux erreurs. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_lock_unlock_errors(GBinFormat *format, bool state) +{ + if (state) + { + g_mutex_lock(&format->error_mutex); +#ifndef NDEBUG + g_atomic_int_set(&format->error_locked, 1); +#endif + } + else + { +#ifndef NDEBUG + g_atomic_int_set(&format->error_locked, 0); +#endif + g_mutex_unlock(&format->error_mutex); + } + +} + + +/****************************************************************************** +* * +* Paramètres : format = architecture concernée par la procédure. * +* index = indice du problème visé. * +* type = type d'erreur retrouvée. * +* addr = localisation associée. * +* desc = éventuelle description humaine de description. * +* * +* Description : Etend la liste des soucis détectés avec de nouvelles infos. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_binary_format_add_error(GBinFormat *format, BinaryFormatError type, const vmpa2t *addr, const char *desc) +{ + fmt_error *error; /* Raccourci de confort */ + + g_binary_format_lock_errors(format); + + format->errors = realloc(format->errors, ++format->error_count * sizeof(fmt_error)); + + error = &format->errors[format->error_count - 1]; + + error->type = type; + + copy_vmpa(&error->addr, addr); + + if (desc != NULL) + error->desc = strdup(desc); + else + error->desc = NULL; + + g_binary_format_unlock_errors(format); + +} + + +/****************************************************************************** +* * +* Paramètres : format = architecture à consulter durant la procédure. * +* * +* Description : Indique le nombre d'erreurs relevées au niveau assembleur. * +* * +* Retour : Nombre d'erreurs en stock. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_binary_format_count_errors(GBinFormat *format) +{ + size_t result; /* Quantité à retourner */ + + assert(g_atomic_int_get(&format->error_locked) == 1); + + result = format->error_count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = architecture concernée par la procédure. * +* index = indice du problème visé. * +* type = type d'erreur retrouvée. [OUT] * +* addr = localisation associée. [OUT] * +* desc = éventuelle description humaine de description. [OUT]* +* * +* Description : Fournit les éléments concernant un soucis détecté. * +* * +* Retour : Validité des informations renseignées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_get_error(GBinFormat *format, size_t index, BinaryFormatError *type, vmpa2t *addr, char **desc) +{ + bool result; /* Bilan à retourner */ + fmt_error *error; /* Raccourci de confort */ + + assert(g_atomic_int_get(&format->error_locked) == 1); + + result = (index < format->error_count); + + assert(result); + + if (result) + { + error = &format->errors[index]; + + *type = error->type; + + copy_vmpa(addr, &error->addr); + + if (error->desc != NULL) + *desc = strdup(error->desc); + else + *desc = NULL; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format de binaire concerné par la procédure. * +* pbuf = zone tampon à vider. * +* * +* Description : Charge les erreurs de chargement depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_format_load_errors(GBinFormat *format, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + uleb128_t value; /* Valeur ULEB128 à charger */ + size_t i; /* Boucle de parcours */ + fmt_error *error; /* Raccourci de confort */ + rle_string str; /* Chaîne à charger */ + + g_binary_format_lock_errors(format); + + result = unpack_uleb128(&value, pbuf); + if (!result) goto exit; + + format->error_count = value; + + format->errors = calloc(format->error_count, sizeof(fmt_error)); + + for (i = 0; i < format->error_count && result; i++) + { + error = &format->errors[i]; + + result = unpack_uleb128(&value, pbuf); + if (!result) break; + + error->type = value; + + result = unpack_vmpa(&error->addr, pbuf); + if (!result) break; + + setup_empty_rle_string(&str); + + result = unpack_rle_string(&str, pbuf); + if (!result) break; + + if (get_rle_string(&str) != NULL) + error->desc = strdup(get_rle_string(&str)); + + exit_rle_string(&str); + + } + + exit: + + g_binary_format_unlock_errors(format); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : format = format de binaire concerné par la procédure. * +* pbuf = zone tampon à remplir. * +* * +* Description : Sauvegarde les erreurs de chargement dans une mémoire tampon.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_format_store_errors(GBinFormat *format, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + fmt_error *error; /* Raccourci de confort */ + rle_string str; /* Chaîne à conserver */ + + g_binary_format_lock_errors(format); + + result = pack_uleb128((uleb128_t []){ format->error_count }, pbuf); + + for (i = 0; i < format->error_count && result; i++) + { + error = &format->errors[i]; + + result = pack_uleb128((uleb128_t []){ error->type }, pbuf); + if (!result) break; + + result = pack_vmpa(&error->addr, pbuf); + if (!result) break; + + init_static_rle_string(&str, error->desc); + + result = pack_rle_string(&str, pbuf); + + exit_rle_string(&str); + + } + + g_binary_format_unlock_errors(format); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * +* * +* Description : Charge un format depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_format_load(GBinFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + fmt_extra_data_t *extra; /* Données insérées à consulter*/ + uleb128_t value; /* Valeur ULEB128 à charger */ + rle_string str; /* Chaîne à charger */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + LOCK_GOBJECT_EXTRA(extra); + + result = unpack_uleb128(&value, pbuf); + + if (result) + extra->flags = value; + + UNLOCK_GOBJECT_EXTRA(extra); + + if (result) + result = g_binary_format_load_start_points(format, pbuf); + + if (result) + { + setup_empty_rle_string(&str); + + result = unpack_rle_string(&str, pbuf); + + if (result) + result = (get_rle_string(&str) != NULL); + + if (result) + format->demangler = get_compiler_demangler_for_key(get_rle_string(&str)); + + if (result) + result = (format->demangler != NULL); + + exit_rle_string(&str); + + } + + + + + + if (result) + result = g_binary_format_load_errors(format, pbuf); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à remplir. * +* * +* Description : Sauvegarde un format dans une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_binary_format_store(GBinFormat *format, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + fmt_extra_data_t *extra; /* Données insérées à consulter*/ + char *key; /* Désignation du décodeur */ + rle_string str; /* Chaîne à conserver */ + + extra = GET_BIN_FORMAT_EXTRA(format); + + LOCK_GOBJECT_EXTRA(extra); + + result = pack_uleb128((uleb128_t []){ extra->flags }, pbuf); + + UNLOCK_GOBJECT_EXTRA(extra); + + if (result) + result = g_binary_format_store_start_points(format, pbuf); + + if (result) + { + key = g_compiler_demangler_get_key(format->demangler); + init_dynamic_rle_string(&str, key); + + result = pack_rle_string(&str, pbuf); + + exit_rle_string(&str); + + } + + + + + + + if (result) + result = g_binary_format_store_errors(format, pbuf); + + return result; + +} diff --git a/src/format/program.h b/src/format/program.h new file mode 100644 index 0000000..f9aa430 --- /dev/null +++ b/src/format/program.h @@ -0,0 +1,200 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * format.h - prototypes pour le support des différents formats binaires + * + * Copyright (C) 2009-2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#ifndef _FORMAT_FORMAT_H +#define _FORMAT_FORMAT_H + + +#include +#include +#include + + +#include "symbol.h" +#include "../analysis/content.h" +#include "../arch/context.h" +#include "../glibext/delayed.h" +#include "../glibext/notifier.h" + + + +/* Depuis ../mangling/demangler.h : Décodeur de désignations générique (instance) */ +typedef struct _GCompDemangler GCompDemangler; + +/* Indications supplémentaires liées aux formats */ +typedef enum _FormatFlag +{ + FFL_NONE = (0 << 0), /* Aucune propriété */ + FFL_RUN_IN_KERNEL_SPACE = (1 << 0), /* Exécution en espace noyau */ + + FFL_MASK = (1 << 1) - 1, /* Indication de nature */ + +} FormatFlag; + + +#define G_TYPE_BIN_FORMAT g_binary_format_get_type() +#define G_BIN_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BIN_FORMAT, GBinFormat)) +#define G_IS_BIN_FORMAT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BIN_FORMAT)) +#define G_BIN_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BIN_FORMAT, GBinFormatClass)) +#define G_IS_BIN_FORMAT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BIN_FORMAT)) +#define G_BIN_FORMAT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BIN_FORMAT, GBinFormatClass)) + + +/* Format binaire générique (instance) */ +typedef struct _GBinFormat GBinFormat; + +/* Format binaire générique (classe) */ +typedef struct _GBinFormatClass GBinFormatClass; + + +/* Indique le type défini pour un format binaire générique. */ +GType g_binary_format_get_type(void); + +/* Ajoute une information complémentaire à un format. */ +bool g_binary_format_set_flag(GBinFormat *, FormatFlag); + +/* Retire une information complémentaire à un format. */ +bool g_binary_format_unset_flag(GBinFormat *, FormatFlag); + +/* Détermine si un format possède un fanion particulier. */ +bool g_binary_format_has_flag(const GBinFormat *, FormatFlag); + +/* Fournit les particularités du format. */ +FormatFlag g_binary_format_get_flags(const GBinFormat *); + +/* Indique le boutisme employé par le format binaire analysé. */ +SourceEndian g_binary_format_get_endianness(const GBinFormat *); + +/* Enregistre une adresse comme début d'une zone de code. */ +void g_binary_format_register_code_point(GBinFormat *, virt_t, DisassPriorityLevel); + +/* Intègre dans un contexte les informations tirées d'un format. */ +void g_binary_format_preload_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); + +/* Définit les points de départ d'un contexte de désassemblage. */ +void g_binary_format_activate_disassembling_context(GBinFormat *, GProcContext *, GtkStatusStack *); + + + +/* ------------------------------ DECODAGE DE SYMBOLES ------------------------------ */ + + +/* Fournit le décodeur de symboles privilégié pour un format. */ +GCompDemangler *g_binary_format_get_demangler(const GBinFormat *); + + + +/* ---------------------- RASSEMBLEMENT ET GESTION DE SYMBOLES ---------------------- */ + + +/* Protège ou lève la protection de l'accès aux symboles. */ +void g_binary_format_lock_unlock_symbols_rd(GBinFormat *, bool); + +#define g_binary_format_lock_symbols_rd(f) g_binary_format_lock_unlock_symbols_rd(f, true) +#define g_binary_format_unlock_symbols_rd(f) g_binary_format_lock_unlock_symbols_rd(f, false) + +/* Protège ou lève la protection de l'accès aux symboles. */ +void g_binary_format_lock_unlock_symbols_wr(GBinFormat *, bool); + +#define g_binary_format_lock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, true) +#define g_binary_format_unlock_symbols_wr(f) g_binary_format_lock_unlock_symbols_wr(f, false) + +/* Assure qu'un verrou est bien posé pour l'accès aux symboles. */ +#ifndef NDEBUG +void g_binary_format_check_for_symbols_lock(const GBinFormat *); +#endif + +/* Fournit la marque de dernière modification des symboles. */ +unsigned int g_binary_format_get_symbols_stamp(const GBinFormat *); + +/* Compte le nombre de symboles représentés. */ +size_t g_binary_format_count_symbols(const GBinFormat *); + +/* Fournit un symbole lié à un format. */ +GBinSymbol *g_binary_format_get_symbol(const GBinFormat *, size_t); + +/* Ajoute un symbole à la collection du format binaire. */ +bool g_binary_format_add_symbol(GBinFormat *, GBinSymbol *); + +/* Ajoute plusieurs symboles à la collection du format binaire. */ +bool g_binary_format_add_symbols(GBinFormat *, GBinSymbol **, size_t); + +/* Retire un symbole de la collection du format binaire. */ +void g_binary_format_remove_symbol(GBinFormat *, GBinSymbol *); + +/* Recherche le symbole correspondant à une étiquette. */ +bool g_binary_format_find_symbol_by_label(GBinFormat *, const char *, GBinSymbol **); + +/* Recherche l'indice du symbole correspondant à une adresse. */ +bool g_binary_format_find_symbol_index_at(GBinFormat *, const vmpa2t *, size_t *); + +/* Recherche le symbole correspondant à une adresse. */ +bool g_binary_format_find_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); + +/* Recherche le symbole contenant une adresse. */ +bool g_binary_format_find_symbol_for(GBinFormat *, const vmpa2t *, GBinSymbol **); + +/* Recherche le symbole suivant celui lié à une adresse. */ +bool g_binary_format_find_next_symbol_at(GBinFormat *, const vmpa2t *, GBinSymbol **); + +/* Recherche le premier symbole inclus dans une zone mémoire. */ +bool g_binary_format_find_first_symbol_inside(GBinFormat *, const mrange_t *, size_t *); + +/* Recherche le symbole correspondant à une adresse. */ +bool g_binary_format_resolve_symbol(GBinFormat *, const vmpa2t *, bool, GBinSymbol **, phys_t *); + + + +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ + + +/* Types d'erreurs détectées */ + +#define FMT_ERROR(idx) ((idx << 2) | (0 << 0)) + +typedef enum _BinaryFormatError +{ + BFE_SPECIFICATION = FMT_ERROR(0), /* Non respect des specs */ + BFE_STRUCTURE = FMT_ERROR(1) /* Code non reconnu */ + +} BinaryFormatError; + + +/* Protège ou lève la protection de l'accès aux erreurs. */ +void g_binary_format_lock_unlock_errors(GBinFormat *, bool); + +#define g_binary_format_lock_errors(f) g_binary_format_lock_unlock_errors(f, true) +#define g_binary_format_unlock_errors(f) g_binary_format_lock_unlock_errors(f, false) + +/* Etend la liste des soucis détectés avec de nouvelles infos. */ +void g_binary_format_add_error(GBinFormat *, BinaryFormatError, const vmpa2t *, const char *); + +/* Indique le nombre d'erreurs relevées au niveau assembleur. */ +size_t g_binary_format_count_errors(GBinFormat *); + +/* Fournit les éléments concernant un soucis détecté. */ +bool g_binary_format_get_error(GBinFormat *, size_t, BinaryFormatError *, vmpa2t *, char **); + + + +#endif /* _FORMAT_FORMAT_H */ diff --git a/tests/format/format.py b/tests/format/format.py deleted file mode 100644 index b6aad8f..0000000 --- a/tests/format/format.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/python3-dbg -# -*- coding: utf-8 -*- - - -# Tests minimalistes pour valider la gestion des erreurs relevées. - - -from chrysacase import ChrysalideTestCase -from pychrysalide.arch import vmpa, mrange -from pychrysalide.format import BinFormat -from pychrysalide.format import BinSymbol -import os -import sys - - -class SimpleFormat(BinFormat): - pass - - -class TestFormatErrors(ChrysalideTestCase): - """TestCase for format.BinFormat.""" - - - def create_fake_symbol(self, index): - saddr = vmpa(index * 0x10, vmpa.VMPA_NO_VIRTUAL) - srange = mrange(saddr, 0x3) - symbol = BinSymbol(BinSymbol.STP_ENTRY_POINT, srange) - return symbol - - - def testBasicSymbolOperations(self): - """Deal with the basic operations related to symbols in a binary format.""" - - sf = SimpleFormat() - - self.assertTrue(len(list(sf.symbols)) == 0) - - symbols = [ self.create_fake_symbol(i) for i in range(4) ] - s0, s1, s2, s3 = symbols - - for s in symbols: - sf.add_symbol(s) - - self.assertTrue(len(list(sf.symbols)) == len(symbols)) - - sf.remove_symbol(s2) - - self.assertTrue(list(sf.symbols) == [s0, s1, s3]) - - - def testBadParamsForAdding(self): - """Check if bad parameters fail for adding a new symbol.""" - - sf = SimpleFormat() - - with self.assertRaises(TypeError): - sf.add_symbol('s') - - - def testWrongRemoval(self): - """Try to remove a wrong symbol from a format.""" - - sf = SimpleFormat() - - s23 = self.create_fake_symbol(23) - sf.remove_symbol(s23) diff --git a/tests/format/program.py b/tests/format/program.py new file mode 100644 index 0000000..b6aad8f --- /dev/null +++ b/tests/format/program.py @@ -0,0 +1,66 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +# Tests minimalistes pour valider la gestion des erreurs relevées. + + +from chrysacase import ChrysalideTestCase +from pychrysalide.arch import vmpa, mrange +from pychrysalide.format import BinFormat +from pychrysalide.format import BinSymbol +import os +import sys + + +class SimpleFormat(BinFormat): + pass + + +class TestFormatErrors(ChrysalideTestCase): + """TestCase for format.BinFormat.""" + + + def create_fake_symbol(self, index): + saddr = vmpa(index * 0x10, vmpa.VMPA_NO_VIRTUAL) + srange = mrange(saddr, 0x3) + symbol = BinSymbol(BinSymbol.STP_ENTRY_POINT, srange) + return symbol + + + def testBasicSymbolOperations(self): + """Deal with the basic operations related to symbols in a binary format.""" + + sf = SimpleFormat() + + self.assertTrue(len(list(sf.symbols)) == 0) + + symbols = [ self.create_fake_symbol(i) for i in range(4) ] + s0, s1, s2, s3 = symbols + + for s in symbols: + sf.add_symbol(s) + + self.assertTrue(len(list(sf.symbols)) == len(symbols)) + + sf.remove_symbol(s2) + + self.assertTrue(list(sf.symbols) == [s0, s1, s3]) + + + def testBadParamsForAdding(self): + """Check if bad parameters fail for adding a new symbol.""" + + sf = SimpleFormat() + + with self.assertRaises(TypeError): + sf.add_symbol('s') + + + def testWrongRemoval(self): + """Try to remove a wrong symbol from a format.""" + + sf = SimpleFormat() + + s23 = self.create_fake_symbol(23) + sf.remove_symbol(s23) -- cgit v0.11.2-87-g4458