From a9328553fc558bca2e75f2c93b35acc5518d9568 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 7 Aug 2017 23:50:38 +0200 Subject: Stored all errors detected when loading and disassembling a binary file. --- ChangeLog | 24 +++++ plugins/pychrysa/arch/processor.c | 153 +++++++++++++++++++++++++- plugins/pychrysa/format/format.c | 157 +++++++++++++++++++++++++++ src/analysis/disass/output.c | 8 ++ src/arch/processor-int.h | 19 +++- src/arch/processor.c | 171 ++++++++++++++++++++++++++++- src/arch/processor.h | 29 +++++ src/format/format-int.h | 18 ++++ src/format/format.c | 219 +++++++++++++++++++++++++++++++++++++- src/format/format.h | 28 +++++ src/format/preload.c | 14 ++- tests/arch/errors.py | 35 ++++++ tests/format/errors.py | 58 ++++++++++ 13 files changed, 923 insertions(+), 10 deletions(-) create mode 100644 tests/arch/errors.py create mode 100644 tests/format/errors.py diff --git a/ChangeLog b/ChangeLog index f33c247..4981236 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +17-08-07 Cyrille Bagard + + * plugins/pychrysa/arch/processor.c: + * plugins/pychrysa/format/format.c: + Update the Python bindings. + + * src/analysis/disass/output.c: + Update code. + + * src/arch/processor-int.h: + * src/arch/processor.c: + * src/arch/processor.h: + * src/format/format-int.h: + * src/format/format.c: + * src/format/format.h: + Store all errors detected when loading and disassembling a binary file. + + * src/format/preload.c: + Fix bugs when freeing the memory used by preloaded info. + + * tests/arch/errors.py: + * tests/format/errors.py: + New entries: extend the test suite. + 17-08-06 Cyrille Bagard * src/gui/panels/panel-int.h: diff --git a/plugins/pychrysa/arch/processor.c b/plugins/pychrysa/arch/processor.c index c3d744b..4470e78 100644 --- a/plugins/pychrysa/arch/processor.c +++ b/plugins/pychrysa/arch/processor.c @@ -55,12 +55,18 @@ +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ +/* Etend la liste des soucis détectés avec de nouvelles infos. */ +static PyObject *py_arch_processor_add_error(PyObject *, PyObject *); + +/* Fournit les éléments concernant tous les soucis détectés. */ +static PyObject *py_arch_processor_get_errors(PyObject *, void *); -/* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */ +/* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */ /* Fournit les instructions désassemblées pour une architecture. */ @@ -74,6 +80,109 @@ static PyObject *py_arch_processor_find_instr_by_addr(PyObject *, PyObject *); + + +/* Définit les constantes pour les types d'erreurs. */ +static bool define_python_arch_processor_constants(PyTypeObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/* 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_arch_processor_add_error(PyObject *self, PyObject *args) +{ + ArchProcessingError type; /* Type d'erreur détectée */ + vmpa2t addr; /* Position d'une erreur */ + char *desc; /* Description d'une erreur */ + int ret; /* Bilan de lecture des args. */ + GArchProcessor *proc; /* Processeur manipulé */ + + ret = PyArg_ParseTuple(args, "IO&s", &type, convert_any_to_vmpa, &addr, &desc); + if (!ret) return NULL; + + proc = G_ARCH_PROCESSOR(pygobject_get(self)); + + g_arch_processor_add_error(proc, type, &addr, desc); + + 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_arch_processor_get_errors(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GArchProcessor *proc; /* Architecture visée */ + size_t count; /* Nombre d'éléments à traiter */ + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + bool status; /* Bilan d'un appel */ +#endif + ArchProcessingError type; /* Type d'erreur détectée */ + vmpa2t addr; /* Position d'une erreur */ + char *desc; /* Description d'une erreur */ + PyObject *error; /* Nouvelle erreur à rajouter */ + + proc = G_ARCH_PROCESSOR(pygobject_get(self)); + + g_arch_processor_lock_errors(proc); + + count = g_arch_processor_count_errors(proc); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { +#ifndef NDEBUG + status = g_arch_processor_get_error(proc, i, &type, &addr, &desc); + assert(status); +#else + g_arch_processor_get_error(proc, i, &type, &addr, &desc); +#endif + + error = Py_BuildValue("IO&s", type, build_from_internal_vmpa, &addr, desc); + + PyTuple_SetItem(result, i, error); + + } + + g_arch_processor_unlock_errors(proc); + + return result; + +} + + + /* ---------------------------------------------------------------------------------- */ /* MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES */ /* ---------------------------------------------------------------------------------- */ @@ -227,6 +336,36 @@ static PyObject *py_arch_processor_find_instr_by_addr(PyObject *self, PyObject * } + + + + +/****************************************************************************** +* * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les types d'erreurs. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool define_python_arch_processor_constants(PyTypeObject *obj_type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + result &= PyDict_AddIntMacro(obj_type, APE_DISASSEMBLY); + result &= PyDict_AddIntMacro(obj_type, APE_LABEL); + + return result; + +} + + /****************************************************************************** * * * Paramètres : - * @@ -243,6 +382,11 @@ PyTypeObject *get_python_arch_processor_type(void) { static PyMethodDef py_arch_processor_methods[] = { { + "add_error", py_arch_processor_add_error, + METH_VARARGS, + "add_error($self, type, addr, desc, /)\n--\n\nExtend the list of detected disassembling errors." + }, + { "find_instr_by_addr", py_arch_processor_find_instr_by_addr, METH_VARARGS, "find_instr_by_addr($self, addr, /)\n--\n\nLook for an instruction located at a given address." @@ -252,6 +396,10 @@ PyTypeObject *get_python_arch_processor_type(void) static PyGetSetDef py_arch_processor_getseters[] = { { + "errors", py_arch_processor_get_errors, NULL, + "List of all detected errors which occurred during the disassembling process.", NULL + }, + { "instrs", py_arch_processor_get_instrs, py_arch_processor_set_instrs, "Give access to the disassembled instructions run by the current processor.", NULL }, @@ -303,6 +451,9 @@ bool register_python_arch_processor(PyObject *module) if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, py_arch_processor_type, &PyGObject_Type)) return false; + if (!define_python_arch_processor_constants(py_arch_processor_type)) + return false; + return true; } diff --git a/plugins/pychrysa/format/format.c b/plugins/pychrysa/format/format.c index cc9e819..773b928 100644 --- a/plugins/pychrysa/format/format.c +++ b/plugins/pychrysa/format/format.c @@ -84,6 +84,25 @@ 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 *); + + + + + + +/* Définit les constantes pour les types d'erreurs. */ +static bool define_python_binary_format_constants(PyTypeObject *); + + + /* ---------------------------------------------------------------------------------- */ /* PARCOURS DE SYMBOLES DE BINAIRES */ /* ---------------------------------------------------------------------------------- */ @@ -538,6 +557,132 @@ static PyObject *py_binary_format_get_symbols(PyObject *self, void *closure) } + +/* ---------------------------------------------------------------------------------- */ +/* 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 */ + char *desc; /* Description d'une erreur */ + int ret; /* Bilan de lecture des args. */ + GBinFormat *format; /* Format binaire manipulé */ + + ret = PyArg_ParseTuple(args, "IO&s", &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); + + 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 *error; /* Nouvelle erreur à rajouter */ + + 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 + + error = Py_BuildValue("IO&s", type, build_from_internal_vmpa, &addr, desc); + + PyTuple_SetItem(result, i, error); + + } + + g_binary_format_unlock_errors(format); + + return result; + +} + + + + + + + +/****************************************************************************** +* * +* Paramètres : obj_type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les types d'erreurs. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool define_python_binary_format_constants(PyTypeObject *obj_type) +{ + bool result; /* Bilan à retourner */ + + result = true; + + result &= PyDict_AddIntMacro(obj_type, BFE_STRUCTURE); + + return result; + +} + + /****************************************************************************** * * * Paramètres : - * @@ -573,6 +718,11 @@ PyTypeObject *get_python_binary_format_type(void) METH_VARARGS, "resolve_symbol($self, addr, strict, /)\n--\n\nSearch a position inside a routine by a given address." }, + { + "add_error", py_binary_format_add_error, + METH_VARARGS, + "add_error($self, type, addr, desc, /)\n--\n\nExtend the list of detected disassembling errors." + }, { NULL } }; @@ -585,6 +735,10 @@ PyTypeObject *get_python_binary_format_type(void) "symbols", py_binary_format_get_symbols, NULL, "Iterable list of all symbols found in the binary format.", NULL }, + { + "errors", py_binary_format_get_errors, NULL, + "List of all detected errors which occurred while loading the binary.", NULL + }, { NULL } }; @@ -635,6 +789,9 @@ bool register_python_binary_format(PyObject *module) if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, py_bin_format_type, &PyGObject_Type)) return false; + if (!define_python_binary_format_constants(py_bin_format_type)) + return false; + return true; } diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c index 063280c..8e74d1c 100644 --- a/src/analysis/disass/output.c +++ b/src/analysis/disass/output.c @@ -83,6 +83,7 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang, GLineGenerator *generator; /* Générateur de contenu ajouté*/ const vmpa2t *saddr; /* Adresse de symbole */ int compared; /* Bilan d'une comparaison */ + char *errmsg; /* Description d'une erreur */ SymbolType stype; /* Type de symbole trouvé */ vmpa2t intro_addr; /* Adresse de début de code */ vmpa2t outro_addr; /* Adresse de fin de code */ @@ -220,6 +221,13 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang, _("Unable to find a proper location for symbol '%s' @ 0x%08x"), g_binary_symbol_get_label(symbols[sym_index]), get_phy_addr(saddr)); + asprintf(&errmsg, _("Unable to find a proper location for symbol '%s'"), + g_binary_symbol_get_label(symbols[sym_index])); + + g_arch_processor_add_error(proc, APE_LABEL, saddr, errmsg); + + free(errmsg); + _missing++; if (++sym_index == sym_count) diff --git a/src/arch/processor-int.h b/src/arch/processor-int.h index 0a95fde..a308bb8 100644 --- a/src/arch/processor-int.h +++ b/src/arch/processor-int.h @@ -59,6 +59,16 @@ typedef GArchInstruction * (* disass_instr_fc) (const GArchProcessor *, GProcCon +/* Description d'une erreur */ +typedef struct _proc_error +{ + ArchProcessingError type; /* Type d'erreur */ + + vmpa2t addr; /* Localisation du problème */ + char *desc; /* Description du soucis */ + +} proc_error; + /* Couverture d'un groupe d'instructions */ struct _instr_coverage { @@ -70,8 +80,6 @@ struct _instr_coverage }; - - /* Définition générique d'un processeur d'architecture (instance) */ struct _GArchProcessor { @@ -92,6 +100,13 @@ struct _GArchProcessor gint locked; /* Statut d'accès à la liste */ #endif + proc_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 + instr_coverage *coverages; /* Liste de couvertures */ size_t cov_allocated; /* Taille de la liste allouée */ size_t cov_count; /* Taille de la liste utilisée */ diff --git a/src/arch/processor.c b/src/arch/processor.c index 38c39e6..21b6c49 100644 --- a/src/arch/processor.c +++ b/src/arch/processor.c @@ -27,6 +27,7 @@ #include #include #include +#include @@ -129,10 +130,17 @@ static void g_arch_processor_class_init(GArchProcessorClass *klass) static void g_arch_processor_init(GArchProcessor *proc) { + g_mutex_init(&proc->mutex); #ifndef DEBUG g_atomic_int_set(&proc->locked, 0); #endif - g_mutex_init(&proc->mutex); + + proc->errors = NULL; + proc->error_count = 0; + g_mutex_init(&proc->error_mutex); +#ifndef DEBUG + g_atomic_int_set(&proc->error_locked, 0); +#endif proc->coverages = NULL; proc->cov_allocated = 0; @@ -157,6 +165,8 @@ static void g_arch_processor_dispose(GArchProcessor *proc) { g_mutex_clear(&proc->mutex); + g_mutex_clear(&proc->error_mutex); + G_OBJECT_CLASS(g_arch_processor_parent_class)->dispose(G_OBJECT(proc)); } @@ -176,6 +186,18 @@ static void g_arch_processor_dispose(GArchProcessor *proc) static void g_arch_processor_finalize(GArchProcessor *proc) { + size_t i; /* Boucle de parcours */ + + if (proc->errors != NULL) + { + for (i = 0; i < proc->error_count; i++) + if (proc->errors[i].desc != NULL) + free(proc->errors[i].desc); + + free(proc->errors); + + } + G_OBJECT_CLASS(g_arch_processor_parent_class)->finalize(G_OBJECT(proc)); } @@ -498,6 +520,153 @@ GArchInstruction *g_arch_processor_get_instruction(const GArchProcessor *proc, s /* ---------------------------------------------------------------------------------- */ +/* CONSERVATION DES SOUCIS DURANT LE CHARGEMENT */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : proc = 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_arch_processor_lock_unlock_errors(GArchProcessor *proc, bool state) +{ + if (state) + { + g_mutex_lock(&proc->error_mutex); + g_atomic_int_set(&proc->error_locked, 1); + } + else + { + g_atomic_int_set(&proc->error_locked, 0); + g_mutex_unlock(&proc->error_mutex); + } + +} + + +/****************************************************************************** +* * +* Paramètres : proc = 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_arch_processor_add_error(GArchProcessor *proc, ArchProcessingError type, const vmpa2t *addr, const char *desc) +{ + proc_error *error; /* Raccourci de confort */ + + g_arch_processor_lock_errors(proc); + + proc->errors = realloc(proc->errors, ++proc->error_count * sizeof(proc_error)); + + error = &proc->errors[proc->error_count - 1]; + + error->type = type; + + copy_vmpa(&error->addr, addr); + + if (desc != NULL) + error->desc = strdup(desc); + else + error->desc = NULL; + + g_arch_processor_unlock_errors(proc); + +} + + +/****************************************************************************** +* * +* Paramètres : proc = 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_arch_processor_count_errors(GArchProcessor *proc) +{ + size_t result; /* Quantité à retourner */ + + assert(g_atomic_int_get(&proc->error_locked) == 1); + + result = proc->error_count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : proc = 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_arch_processor_get_error(GArchProcessor *proc, size_t index, ArchProcessingError *type, vmpa2t *addr, char **desc) +{ + bool result; /* Bilan à retourner */ + proc_error *error; /* Raccourci de confort */ + + assert(g_atomic_int_get(&proc->error_locked) == 1); + + result = (index < proc->error_count); + + assert(result); + + if (result) + { + error = &proc->errors[index]; + + *type = error->type; + + copy_vmpa(addr, &error->addr); + + if (error->desc != NULL) + *desc = strdup(error->desc); + else + *desc = NULL; + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ /* MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES */ /* ---------------------------------------------------------------------------------- */ diff --git a/src/arch/processor.h b/src/arch/processor.h index 2a8a8c1..87c0738 100644 --- a/src/arch/processor.h +++ b/src/arch/processor.h @@ -98,6 +98,35 @@ GArchInstruction *g_arch_processor_get_instruction(const GArchProcessor *, size_ +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ + + +/* Types d'erreurs détectées */ +typedef enum _ArchProcessingError +{ + APE_DISASSEMBLY = ((0 << 2) | (1 << 0)),/* Code non reconnu */ + APE_LABEL = ((1 << 2) | (1 << 0)) /* Etiquette non référencée */ + +} ArchProcessingError; + + +/* Protège ou lève la protection de l'accès aux erreurs. */ +void g_arch_processor_lock_unlock_errors(GArchProcessor *, bool); + +#define g_arch_processor_lock_errors(p) g_arch_processor_lock_unlock_errors(p, true) +#define g_arch_processor_unlock_errors(p) g_arch_processor_lock_unlock_errors(p, false) + +/* Etend la liste des soucis détectés avec de nouvelles infos. */ +void g_arch_processor_add_error(GArchProcessor *, ArchProcessingError, const vmpa2t *, const char *); + +/* Indique le nombre d'erreurs relevées au niveau assembleur. */ +size_t g_arch_processor_count_errors(GArchProcessor *); + +/* Fournit les éléments concernant un soucis détecté. */ +bool g_arch_processor_get_error(GArchProcessor *, size_t, ArchProcessingError *, vmpa2t *, char **); + + + /* ------------------ MANIPULATIONS DES INSTRUCTIONS DESASSEMBLEES ------------------ */ diff --git a/src/format/format-int.h b/src/format/format-int.h index d50b053..0ab0e85 100644 --- a/src/format/format-int.h +++ b/src/format/format-int.h @@ -47,6 +47,17 @@ typedef void (* format_decompile_fc) (const GBinFormat *, void/*GCodeBuffer*/ *, #define EXTRA_POINT_BLOCK 100 +/* 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 { @@ -74,6 +85,13 @@ struct _GBinFormat size_t def_source; /* Fichier source principal */ format_decompile_fc decompile; /* Décompilation d'un fichier */ + 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) */ diff --git a/src/format/format.c b/src/format/format.c index 5d845e4..293e5da 100644 --- a/src/format/format.c +++ b/src/format/format.c @@ -50,6 +50,12 @@ 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 *); + /* Retire un symbole de la collection du format binaire. */ static void _g_binary_format_remove_symbol(GBinFormat *, size_t); @@ -79,6 +85,12 @@ G_DEFINE_TYPE(GBinFormat, g_binary_format, G_TYPE_OBJECT); static void g_binary_format_class_init(GBinFormatClass *klass) { + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_binary_format_dispose; + object->finalize = (GObjectFinalizeFunc)g_binary_format_finalize; } @@ -103,14 +115,70 @@ static void g_binary_format_init(GBinFormat *format) g_rw_lock_init(&format->syms_lock); + format->errors = NULL; + format->error_count = 0; + g_mutex_init(&format->error_mutex); +#ifndef DEBUG + 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) +{ + g_object_unref(format->info); + + g_rw_lock_clear(&format->syms_lock); -/* FIXME : g_object_unref(format->info); */ + g_mutex_clear(&format->error_mutex); -/* FIXME : g_rw_lock_clear(&format->syms_lock);*/ + 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) +{ + size_t i; /* Boucle de parcours */ + + if (format->errors != NULL) + { + for (i = 0; i < format->error_count; i++) + if (format->errors[i].desc != NULL) + free(format->errors[i].desc); + + free(format->errors); + + } + + G_OBJECT_CLASS(g_binary_format_parent_class)->finalize(G_OBJECT(format)); + +} /****************************************************************************** @@ -964,3 +1032,150 @@ void g_binary_format_decompile(const GBinFormat *format, GCodeBuffer *buffer, co } #endif + + + +/* ---------------------------------------------------------------------------------- */ +/* 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); + g_atomic_int_set(&format->error_locked, 1); + } + else + { + g_atomic_int_set(&format->error_locked, 0); + 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; + +} diff --git a/src/format/format.h b/src/format/format.h index ec78236..3c1bbea 100644 --- a/src/format/format.h +++ b/src/format/format.h @@ -105,4 +105,32 @@ const char * const *g_binary_format_get_source_files(const GBinFormat *, size_t +/* ------------------ CONSERVATION DES SOUCIS DURANT LE CHARGEMENT ------------------ */ + + +/* Types d'erreurs détectées */ +typedef enum _BinaryFormatError +{ + BFE_STRUCTURE = ((0 << 2) | (0 << 0)) /* 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(p) g_binary_format_lock_unlock_errors(p, true) +#define g_binary_format_unlock_errors(p) g_binary_format_lock_unlock_errors(p, 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/preload.c b/src/format/preload.c index 7f7a435..cddc60e 100644 --- a/src/format/preload.c +++ b/src/format/preload.c @@ -105,14 +105,18 @@ static void g_preload_info_init(GPreloadInfo *info) static void g_preload_info_dispose(GPreloadInfo *info) { + size_t count; /* Borne de parcours */ + size_t i; /* Boucle de parcours */ GArchInstruction *instr; /* Instruction à libérer */ GDbComment *comment; /* Commentaire à libérer */ g_preload_info_lock_instructions(info); - while (_g_preload_info_count_instructions(info) > 0) + count = _g_preload_info_count_instructions(info); + + for (i = 0; i < count; i++) { - instr = _g_preload_info_grab_instruction(info, 0); + instr = _g_preload_info_grab_instruction(info, i); g_object_unref(G_OBJECT(instr)); } @@ -122,9 +126,11 @@ static void g_preload_info_dispose(GPreloadInfo *info) g_preload_info_lock_comments(info); - while (_g_preload_info_count_comments(info) > 0) + count = _g_preload_info_count_comments(info); + + for (i = 0; i < count; i++) { - comment = _g_preload_info_grab_comment(info, 0); + comment = _g_preload_info_grab_comment(info, i); g_object_unref(G_OBJECT(comment)); } diff --git a/tests/arch/errors.py b/tests/arch/errors.py new file mode 100644 index 0000000..9d5e273 --- /dev/null +++ b/tests/arch/errors.py @@ -0,0 +1,35 @@ +#!/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 +from pychrysalide.arch import ArchProcessor + + +class TestArchErrors(ChrysalideTestCase): + """TestCase for arch.ArchProcessor errors.""" + + def testBasic(self): + """Perform some sanity tests on architecture error handling.""" + + errlen = 3 + + pattern = [] + + for i in range(errlen): + + addr = vmpa(vmpa.VMPA_NO_PHYSICAL, 0x100 + i * 0x10) + + pattern.append([ArchProcessor.APE_LABEL, addr, 'random desc #%d' % i]) + + proc = ArchProcessor() + + for i in range(errlen): + + proc.add_error(pattern[i][0], pattern[i][1], pattern[i][2]) + + self.assertEqual(len(proc.errors), errlen) diff --git a/tests/format/errors.py b/tests/format/errors.py new file mode 100644 index 0000000..36b7129 --- /dev/null +++ b/tests/format/errors.py @@ -0,0 +1,58 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +# Tests minimalistes pour valider la gestion des erreurs relevées. + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.contents import FileContent +from pychrysalide.arch import vmpa +from pychrysalide.format import BinFormat +from pychrysalide.format.elf import ElfFormat +import os +import sys + + +class TestFormatErrors(ChrysalideTestCase): + """TestCase for format.BinFormat errors.""" + + @classmethod + def setUpClass(cls): + + super(TestFormatErrors, cls).setUpClass() + + cls.log('Compile binary "strings" if needed...') + + fullname = sys.modules[cls.__module__].__file__ + dirpath = os.path.dirname(fullname) + + os.system('make -C %s%self strings 2>&1 > /dev/null' % (dirpath, os.sep)) + + + def testBasic(self): + """Perform some sanity tests on format error handling.""" + + errlen = 3 + + pattern = [] + + for i in range(errlen): + + addr = vmpa(vmpa.VMPA_NO_PHYSICAL, 0x100 + i * 0x10) + + pattern.append([BinFormat.BFE_STRUCTURE, addr, 'random desc #%d' % i]) + + fullname = sys.modules[self.__class__.__module__].__file__ + filename = os.path.basename(fullname) + + baselen = len(fullname) - len(filename) + + cnt = FileContent(fullname[:baselen] + 'elf' + os.sep + 'strings') + fmt = ElfFormat(cnt, None, None) + + for i in range(errlen): + + fmt.add_error(pattern[i][0], pattern[i][1], pattern[i][2]) + + self.assertEqual(len(fmt.errors), errlen) -- cgit v0.11.2-87-g4458