diff options
Diffstat (limited to 'src/debug/break.c')
-rw-r--r-- | src/debug/break.c | 489 |
1 files changed, 256 insertions, 233 deletions
diff --git a/src/debug/break.c b/src/debug/break.c index 19eb787..1d4c2d3 100644 --- a/src/debug/break.c +++ b/src/debug/break.c @@ -24,114 +24,20 @@ #include "break.h" +#include <assert.h> #include <malloc.h> -#include <string.h> -#include "../common/dllist.h" +#include "break-int.h" - -/* --------------------------- GESTION DES POINTS D'ARRET --------------------------- */ - - -/* Propriétés d'un point d'arrêt (instance) */ -struct _GBreakPoint -{ - GObject parent; /* A laisser en premier */ - - DL_LIST_ITEM(link); /* Maillon de liste chaînée */ - - vmpa_t address; /* Adresse où s'arrêter */ - - bool is_enabled; /* Statut d'activité */ - -}; - -/* Propriétés d'un point d'arrêt (classe) */ -struct _GBreakPointClass -{ - GObjectClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* changed) (GBreakPoint *); - -}; - - -#define bp_list_add_tail(new, head) dl_list_add_tail(new, head, GBreakPoint, link) -#define bp_list_del(item, head) dl_list_del(item, head, GBreakPoint, link) -#define bp_list_for_each(pos, head) dl_list_for_each(pos, head, GBreakPoint, link) -#define bp_list_for_each_safe(pos, head, next) dl_list_for_each_safe(pos, head, next, GBreakPoint, link) - - -/* Initialise la classe des propriétés d'un point d'arrêt. */ -static void g_break_point_class_init(GBreakPointClass *); - -/* Initialise des propriétés d'un point d'arrêt. */ -static void g_break_point_init(GBreakPoint *); - - - - - - -/* ---------------------------- GROUPE DE POINTS D'ARRET ---------------------------- */ - - -/* Propriétés d'un groupe de points d'arrêt (instance) */ -struct _GBreakGroup -{ - GObject parent; /* A laisser en premier */ - - char *name; /* Désignation humaine */ - - GBreakPoint *points; /* Liste de points d'arrêt */ - -}; - -/* Propriétés d'un groupe de points d'arrêt (classe) */ -struct _GBreakGroupClass -{ - GObjectClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* added) (GBreakGroup *, GBreakPoint *); - void (* removed) (GBreakGroup *, GBreakPoint *); - -}; - - -/* Initialise la classe des groupes de points d'arrêt. */ -static void g_break_group_class_init(GBreakGroupClass *); - -/* Initialise un groupe de points d'arrêt. */ -static void g_break_group_init(GBreakGroup *); - - - - - - - - -/* ---------------------------------------------------------------------------------- */ -/* GESTION DES POINTS D'ARRET */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour des propriétés d'un point d'arrêt. */ -G_DEFINE_TYPE(GBreakPoint, g_break_point, G_TYPE_OBJECT); - - /****************************************************************************** * * -* Paramètres : klass = classe à initialiser. * +* Paramètres : bp = point d'arrêt à initialiser. * +* addr = adresse d'action du point d'arrêt. * * * -* Description : Initialise la classe des propriétés d'un point d'arrêt. * +* Description : Initialise le coeur d'un point d'arrêt. * * * * Retour : - * * * @@ -139,24 +45,20 @@ G_DEFINE_TYPE(GBreakPoint, g_break_point, G_TYPE_OBJECT); * * ******************************************************************************/ -static void g_break_point_class_init(GBreakPointClass *klass) +void init_raw_breakpoint(raw_breakpoint *bp, virt_t addr) { - g_signal_new("changed", - G_TYPE_BREAK_POINT, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBreakPointClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + bp->addr = addr; + + bp->count = 0; } /****************************************************************************** * * -* Paramètres : point = instance à initialiser. * +* Paramètres : bp = point d'arrêt à traiter. * * * -* Description : Initialise des propriétés d'un point d'arrêt. * +* Description : Libère le coeur d'un point d'arrêt. * * * * Retour : - * * * @@ -164,135 +66,133 @@ static void g_break_point_class_init(GBreakPointClass *klass) * * ******************************************************************************/ -static void g_break_point_init(GBreakPoint *point) +void fini_raw_breakpoint(raw_breakpoint *bp) { - DL_LIST_ITEM_INIT(&point->link); + if (bp->count > 1) + free(bp->sources); + + free(bp); } /****************************************************************************** * * -* Paramètres : address = adresse à laquelle s'arrêter. * +* Paramètres : bp = point d'arrêt à consulter. * * * -* Description : Construit un nouveau point d'arrêt. * +* Description : Indique l'adresse du point d'arrêt dans la mémoire ciblée. * * * -* Retour : Point d'arrêt mis en place ou NULL en cas d'échec. * +* Retour : Adresse associée au point d'arrêt. * * * * Remarques : - * * * ******************************************************************************/ -GBreakPoint *g_break_point_new(vmpa_t address) +virt_t get_raw_breakpoint_addr(const raw_breakpoint *bp) { - GBreakPoint *result; /* Adresse à retourner */ - - result = g_object_new(G_TYPE_BREAK_POINT, NULL); - - result->address = address; - - return result; + return bp->addr; } + /****************************************************************************** * * -* Paramètres : point = instance à consulter. * +* Paramètres : bp = point d'arrêt à consulter. * * * -* Description : Fournit l'adresse associée à un point d'arrêt. * +* Description : Fournit l'adresse d'origine d'un point d'arrêt de pas à pas. * * * -* Retour : Adresse associée. * +* Retour : - * * * -* Remarques : - * +* Remarques : Un appel à cette fonction n'est valide que pour un point * +* d'arrêt de type RBO_STEP. * * * ******************************************************************************/ -vmpa_t g_break_point_get_address(const GBreakPoint *point) +virt_t get_raw_breakpoint_prev_addr(const raw_breakpoint *bp) { - return point->address; + virt_t result; /* Localisation à retourner */ + bool found; /* Valide une obtention */ + size_t i; /* Boucle de parcours */ -} + switch (bp->count) + { + case 1: + assert(bp->source.origin == RBO_INTERNAL || bp->source.origin == RBO_STEP); + result = bp->source.previous; + break; + default: + found = false; -/* ---------------------------------------------------------------------------------- */ -/* GROUPE DE POINTS D'ARRET */ -/* ---------------------------------------------------------------------------------- */ + for (i = 0; i < bp->count && !found; i++) + if (bp->sources[i].origin == RBO_INTERNAL || bp->sources[i].origin == RBO_STEP) + { + result = bp->sources[i].previous; + found = true; + } + assert(found); -/* Indique le type défini pour les groupes de points d'errêt. */ -G_DEFINE_TYPE(GBreakGroup, g_break_group, G_TYPE_OBJECT); + break; + } -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des groupes de points d'arrêt. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_break_group_class_init(GBreakGroupClass *klass) -{ - g_signal_new("added", - G_TYPE_BREAK_GROUP, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBreakGroupClass, added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_BREAK_POINT); - - g_signal_new("removed", - G_TYPE_BREAK_GROUP, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GBreakGroupClass, removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_BREAK_POINT); + return result; } /****************************************************************************** * * -* Paramètres : group = instance à initialiser. * +* Paramètres : addr = adresse à consulter. * +* bp = point d'arrêt à consulter. * * * -* Description : Initialise un groupe de point d'arrêt. * +* Description : Effectue une comparaison entre adresse et point d'arrêt. * * * -* Retour : - * +* Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ -static void g_break_group_init(GBreakGroup *group) +int compare_raw_breakpoint_with_addr(const virt_t *addr, const raw_breakpoint **bp) { + int result; /* Bilan à retourner */ + + if (*addr < (*bp)->addr) + result = -1; + + else if (*addr == (*bp)->addr) + result = 0; + + else + result = 1; + + return result; } /****************************************************************************** * * -* Paramètres : - * +* Paramètres : a = premier point d'arrêt à consulter. * +* b = second point d'arrêt à consulter. * * * -* Description : Construit un nouveau groupe de points d'arrêt. * +* Description : Effectue une comparaison entre deux points d'arrêt. * * * -* Retour : Groupe de points d'arrêt mis en place ou NULL en cas d'échec.* +* Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ -GBreakGroup *g_break_group_new(void) +int compare_raw_breakpoints(const raw_breakpoint **a, const raw_breakpoint **b) { - GBreakGroup *result; /* Adresse à retourner */ + int result; /* Bilan à retourner */ - result = g_object_new(G_TYPE_BREAK_GROUP, NULL); + result = compare_raw_breakpoint_with_addr(&(*a)->addr, b); return result; @@ -301,140 +201,263 @@ GBreakGroup *g_break_group_new(void) /****************************************************************************** * * -* Paramètres : group = groupe de points d'arrêt à consulter. * +* Paramètres : bp = point d'arrêt à manipuler. * +* origin = origine de la création du point d'arrêt. * +* tid = identifiant du thread concerné. * +* previous = éventuelle adresse précédent celle du point. * * * -* Description : Fournit la désignation humaine associée à un groupe. * +* Description : Enregistre la source d'un point d'arrêt posé. * * * -* Retour : Désignation humaine associée, jamais NULL. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -const char *g_break_group_get_name(const GBreakGroup *group) +void set_raw_breakpoint_origin(raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid, virt_t previous) { - return group->name; +#ifndef NDEBUG + size_t i; /* Boucle de parcours */ +#endif + bp_source *src; /* Source à définir */ + bp_source tmp; /* Copie temporaire */ + +#ifndef NDEBUG + + if (bp->count == 1) + assert(bp->source.tid != tid || (bp->source.origin & origin) == 0); + + else + for (i = 0; i < bp->count; i++) + if (bp->source.tid == tid) + { + assert((bp->sources[i].origin & origin) == 0); + break; + } + +#endif + + bp->count++; + + switch (bp->count) + { + case 1: + src = &bp->source; + break; + + case 2: + tmp = bp->source; + bp->sources = (bp_source *)calloc(2, sizeof(bp_source)); + bp->sources[0] = tmp; + src = &bp->sources[1]; + break; + + default: + bp->sources = (bp_source *)realloc(bp->sources, bp->count * sizeof(bp_source)); + src = &bp->sources[bp->count - 1]; + break; + + } + + src->origin = origin; + src->tid = tid; + src->previous = previous; } /****************************************************************************** * * -* Paramètres : group = groupe de points d'arrêt à modifier. * -* name = nouveau nom de scène. * +* Paramètres : bp = point d'arrêt à manipuler. * +* origin = origine de la création du point d'arrêt. * +* tid = identifiant du thread concerné. * +* previous = éventuelle adresse précédent celle du point. * * * -* Description : Définit la désignation humaine à associer à un groupe. * +* Description : Oublie la source d'un point d'arrêt posé. * * * -* Retour : Désignation humaine associée, voire NULL. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -void g_break_group_set_name(GBreakGroup *group, const char *name) +void unset_raw_breakpoint_origin(raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid) { - if (group->name != NULL) - free(group->name); + size_t i; /* Boucle de parcours #1 */ + bp_source tmp; /* Copie temporaire */ +#ifndef NDEBUG + size_t j; /* Boucle de parcours #2 */ +#endif - if (name == NULL) - group->name = NULL; + bool has_same_origin(bp_source *src) + { + bool result; - else - group->name = strdup(name); + result = (src->origin == origin && src->tid == tid); + + return result; + + } + + switch (bp->count) + { + case 1: + + if (has_same_origin(&bp->source)) + bp->count = 0; + + break; + + case 2: + + if (has_same_origin(&bp->sources[0])) + { + assert(!has_same_origin(&bp->sources[1])); + + tmp = bp->sources[1]; + + bp->count = 1; + free(bp->sources); + + bp->source = tmp; + + } + + else if (has_same_origin(&bp->sources[1])) + { + assert(!has_same_origin(&bp->sources[0])); + + tmp = bp->sources[0]; + + bp->count = 1; + free(bp->sources); + + bp->source = tmp; + + } + + break; + + default: + + for (i = 0; i < bp->count; i++) + { + if (has_same_origin(&bp->sources[i])) + { + if ((i + 1) < bp->count) + memmove(&bp->sources[i], &bp->sources[i + 1], (bp->count - i - 1) * sizeof(bp_source)); + + bp->sources = (bp_source *)realloc(bp->sources, --bp->count * sizeof(bp_source)); + +#ifndef NDEBUG + for (j = i; j < bp->count; j++) + assert(!has_same_origin(&bp->sources[j])); +#endif + + break; + + } + + } + + break; + + } } /****************************************************************************** * * -* Paramètres : group = groupe de points d'arrêt à consulter. * -* addr = adresse recherchée dans les points d'arrêt. * +* Paramètres : bp = point d'arrêt à manipuler. * +* origin = origine de la création du point d'arrêt. * +* tid = identifiant du thread concerné. * * * -* Description : Indique si une adresse donnée est gérée dans un groupe. * +* Description : Indique si le point d'arrêt correspond à une source donnée. * * * -* Retour : true si l'adresse est gérée ici, false sinon. * +* Retour : Bilan de l'analyse. * * * * Remarques : - * * * ******************************************************************************/ -bool g_break_group_has_address(const GBreakGroup *group, vmpa_t addr) +bool has_raw_breakpoint_origin(const raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid) { - GBreakPoint *iter; /* Boucle de parcours */ + bool result; /* Conclusion à retourner */ + size_t i; /* Boucle de parcours */ + + if (bp->count == 1) + result = (bp->source.tid == tid && (bp->source.origin & origin) != 0); + + else + { + result = false; + + for (i = 0; i < bp->count && !result; i++) + result = (bp->sources[i].tid == tid && (bp->sources[i].origin & origin) != 0); - bp_list_for_each(iter, group->points) - if (g_break_point_get_address(iter) == addr) - return true; + } - return false; + return result; } /****************************************************************************** * * -* Paramètres : group = groupe de points d'arrêt à modifier. * -* addr = adresse mémoire à faire basculer. * +* Paramètres : bp = point d'arrêt à manipuler. * +* origin = origine de la création du point d'arrêt. * +* tid = identifiant du thread concerné. * +* prev = adresse d'instruction qui a conduit à des poses. * * * -* Description : Ajoute ou supprime un point d'arrêt dans un groupe. * +* Description : Indique si le point d'arrêt correspond à une origine donnée. * * * -* Retour : - * +* Retour : Bilan de l'analyse. * * * * Remarques : - * * * ******************************************************************************/ -void g_break_group_toggle_breakpoint(GBreakGroup *group, vmpa_t addr) +bool has_raw_breakpoint_previous_address(const raw_breakpoint *bp, RawBpOrigin origin, dbg_thread_id_t tid, virt_t prev) { - GBreakPoint *iter; /* Boucle de parcours */ - GBreakPoint *next; /* Prochain point de passage */ + bool result; /* Conclusion à retourner */ + size_t i; /* Boucle de parcours */ - /* Suppression d'un éventuel existant */ + if (bp->count == 1) + result = (bp->source.tid == tid && (bp->source.origin & origin) != 0 && bp->source.previous == prev); - bp_list_for_each_safe(iter, &group->points, next) - if (g_break_point_get_address(iter) == addr) - { - g_signal_emit_by_name(group, "removed", iter); - - bp_list_del(iter, &group->points); - g_object_unref(G_OBJECT(iter)); - - return; - - } - - /* Si non trouvé, ajout du nouveau point */ + else + { + result = false; - iter = g_break_point_new(addr); + for (i = 0; i < bp->count && !result; i++) + result = (bp->sources[i].tid == tid && (bp->sources[i].origin & origin) != 0 && bp->sources[i].previous == prev); - bp_list_add_tail(iter, &group->points); + } - g_signal_emit_by_name(group, "added", iter); + return result; } /****************************************************************************** * * -* Paramètres : group = groupe de points d'arrêt à parcourir. * -* func = fonction à appeler à chaque point trouvé. * -* data = éventuelle donnée de l'utilisateur à joindre. * +* Paramètres : bp = point d'arrêt à consulter. * * * -* Description : Parcourt l'ensemble des points d'arrêt d'un groupe donné. * +* Description : Indique si un point d'arrêt a encore une utilité. * * * -* Retour : - * +* Retour : true si le point peut être retiré, false sinon. * * * * Remarques : - * * * ******************************************************************************/ -void g_break_group_for_each(GBreakGroup *group, GExtFunc func, gpointer data) +bool is_breakpoint_useless(const raw_breakpoint *bp) { - GBreakPoint *iter; /* Boucle de parcours */ + bool result; /* Conclusion à faire remonter */ - /* Suppression d'un éventuel existant */ + result = (bp->count == 0); - bp_list_for_each(iter, group->points) - func(group, iter, data); + return result; } |