From 59f319d9a6961a7424c7b32f49aa7ac1045a1d4c Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 20 Apr 2016 14:07:19 +0200 Subject: Protected all concurrent accesses to sources and destinations of instructions. --- plugins/libcsem/exit.c | 3 + src/analysis/blocks/flow.c | 6 ++ src/analysis/disass/dragon.c | 10 +++- src/analysis/disass/links.c | 13 ++++- src/analysis/disass/loop.c | 4 +- src/analysis/disass/macro.c | 2 + src/analysis/disass/rank.c | 4 ++ src/arch/instruction-int.h | 11 +++- src/arch/instruction.c | 130 ++++++++++++++++++++++++++++++++++++++++-- src/arch/instruction.h | 18 ++++++ src/gtkext/graph/nodes/flow.c | 8 +++ src/gui/dialogs/gotox.c | 13 ++++- src/gui/dialogs/gotox.h | 2 +- 13 files changed, 212 insertions(+), 12 deletions(-) diff --git a/plugins/libcsem/exit.c b/plugins/libcsem/exit.c index 1bb4edd..aa3ca18 100644 --- a/plugins/libcsem/exit.c +++ b/plugins/libcsem/exit.c @@ -68,6 +68,7 @@ static void mark_one_kind_of_exit_as_return(const GLoadedBinary *binary, const c instr = g_arch_processor_find_instr_by_address(proc, get_mrange_addr(range)); + g_arch_instruction_rlock_src(instr); count = g_arch_instruction_get_sources(instr, &sources, &types); for (i = 0; i < count; i++) @@ -78,6 +79,8 @@ static void mark_one_kind_of_exit_as_return(const GLoadedBinary *binary, const c } + g_arch_instruction_runlock_src(instr); + g_object_unref(G_OBJECT(proc)); mokoear_done_with_sym: diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c index 9eb9de8..bc14648 100644 --- a/src/analysis/blocks/flow.c +++ b/src/analysis/blocks/flow.c @@ -574,6 +574,7 @@ bool g_flow_block_is_looping_to(GFlowBlock *block, const GInstrBlock *list, GFlo result = (block == target); + g_arch_instruction_rlock_dest(block->last); dcount = g_arch_instruction_get_destinations(block->last, &dests, &types, NULL); for (i = 0; i < dcount && !result; i++) @@ -598,6 +599,8 @@ bool g_flow_block_is_looping_to(GFlowBlock *block, const GInstrBlock *list, GFlo } + g_arch_instruction_runlock_dest(block->last); + return result; } @@ -634,6 +637,7 @@ bool g_flow_block_follow(GFlowBlock *block, const GInstrBlock *list, BlockFollow if (mask & BFP_ENTER) result = callback(block, BFP_ENTER, data); + g_arch_instruction_rlock_dest(block->last); dcount = g_arch_instruction_get_destinations(block->last, &dests, &types, NULL); for (i = 0; i < dcount && result; i++) @@ -661,6 +665,8 @@ bool g_flow_block_follow(GFlowBlock *block, const GInstrBlock *list, BlockFollow } + g_arch_instruction_runlock_dest(block->last); + if (mask & BFP_EXIT) result &= callback(block, BFP_EXIT, data); diff --git a/src/analysis/disass/dragon.c b/src/analysis/disass/dragon.c index fbdecd8..75b8bb7 100644 --- a/src/analysis/disass/dragon.c +++ b/src/analysis/disass/dragon.c @@ -146,8 +146,8 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_ else { + g_arch_instruction_rlock_src(iter); scount = g_arch_instruction_get_sources(iter, NULL, &types); - if (scount == 0) continue; for (i = 0; i < scount; i++) switch (types[i]) @@ -190,6 +190,8 @@ static dragon_node *create_dragon_nodes(const GArchProcessor *proc, const instr_ } + g_arch_instruction_runlock_src(iter); + } @@ -408,6 +410,7 @@ void compute_all_paths(dragon_node *nodes, size_t count) dragon_node *next; /* Noeud suivant dans le code */ size_t id; /* Indice du bit associé */ + g_arch_instruction_rlock_dest(node->last); dcount = g_arch_instruction_get_destinations(node->last, &dests, &types, NULL); for (i = 0; i < dcount; i++) @@ -435,6 +438,8 @@ void compute_all_paths(dragon_node *nodes, size_t count) } + g_arch_instruction_runlock_dest(node->last); + } follow_flow_in_nodes(&nodes[0]); @@ -498,6 +503,7 @@ void compute_all_dominators(dragon_node *nodes, size_t count) set_all_in_bit_field(inter); + g_arch_instruction_rlock_src(node->first); scount = g_arch_instruction_get_sources(node->first, &srcs, &types); //assert(scount > 0); // un 'ret' coupe, le suivant n'a pas de source @@ -530,6 +536,8 @@ void compute_all_dominators(dragon_node *nodes, size_t count) } + g_arch_instruction_runlock_src(node->first); + set_in_bit_field(inter, k, 1); if (!is_bit_field_equal_to(node->bits, inter)) diff --git a/src/analysis/disass/links.c b/src/analysis/disass/links.c index 86663cc..f52029b 100644 --- a/src/analysis/disass/links.c +++ b/src/analysis/disass/links.c @@ -51,6 +51,7 @@ static void convert_immediate_into_target(GArchInstruction *, size_t, const GBin void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev) { + bool has_src; /* Présence de sources ? */ GArchInstruction **others; /* Instructions diverses liées */ InstructionLinkType *types; /* Types de lien existants */ size_t count; /* Nbre de sources affichées */ @@ -61,7 +62,11 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev) * on ne peut pas créer de lien plus naturel que l'existant. */ - if (!g_arch_instruction_has_sources(instr)) + g_arch_instruction_rlock_src(instr); + has_src = g_arch_instruction_has_sources(instr); + g_arch_instruction_runlock_src(instr); + + if (!has_src) return; /** @@ -79,6 +84,7 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev) * On s'assure que le lien naturel est valide. */ + g_arch_instruction_rlock_dest(prev); count = g_arch_instruction_get_destinations(prev, &others, &types, NULL); for (i = 0; i < count; i++) @@ -89,12 +95,15 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev) if (types[i] == ILT_LOOP) break; } + g_arch_instruction_runlock_dest(prev); + if (count > 0 && i < count) return; /** * On vérifie que le lien n'existe pas déjà avant d'en créer un... */ + g_arch_instruction_rlock_src(instr); count = g_arch_instruction_get_sources(instr, &others, &types); for (i = 0; i < count; i++) @@ -103,6 +112,8 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev) if (others[i] == prev && types[i] == ILT_JUMP_IF_FALSE) break; } + g_arch_instruction_runlock_src(instr); + if (i == count) g_arch_instruction_link_with(prev, instr, ILT_EXEC_FLOW); diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c index e7dbbd7..89a4bc9 100644 --- a/src/analysis/disass/loop.c +++ b/src/analysis/disass/loop.c @@ -64,8 +64,8 @@ static void detect_back_edges(dragon_node *nodes, size_t count) get_dragon_node_bounding_instructions(node, NULL, &last); + g_arch_instruction_wlock_dest(last); dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL); - if (dcount == 0) continue; for (i = 0; i < dcount; i++) switch (types[i]) @@ -102,6 +102,8 @@ static void detect_back_edges(dragon_node *nodes, size_t count) } + g_arch_instruction_wunlock_dest(last); + } } diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c index d9d20ee..6ac1fb2 100644 --- a/src/analysis/disass/macro.c +++ b/src/analysis/disass/macro.c @@ -227,6 +227,7 @@ static GInstrBlock *build_instruction_blocks(GArchProcessor *proc, const dragon_ others = NULL; + g_arch_instruction_rlock_dest(last); dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL); for (i = 0; i < dcount && others == NULL; i++) @@ -283,6 +284,7 @@ static GInstrBlock *build_instruction_blocks(GArchProcessor *proc, const dragon_ } + g_arch_instruction_runlock_dest(last); if (others != NULL) { diff --git a/src/analysis/disass/rank.c b/src/analysis/disass/rank.c index 9b9f29e..85d9e66 100644 --- a/src/analysis/disass/rank.c +++ b/src/analysis/disass/rank.c @@ -73,6 +73,8 @@ static bool rank_flow_block(GFlowBlock *block, BlockVisitOrder order, const GIns links = g_instr_block_get_links_block(G_INSTR_BLOCK(block)); g_flow_block_get_boundary(block, NULL, &last); + + g_arch_instruction_rlock_dest(last); dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL); for (i = 0; i < dcount; i++) @@ -170,6 +172,8 @@ static bool rank_flow_block(GFlowBlock *block, BlockVisitOrder order, const GIns } + g_arch_instruction_runlock_dest(last); + return true; } diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h index eca2807..69cdc8a 100644 --- a/src/arch/instruction-int.h +++ b/src/arch/instruction-int.h @@ -80,10 +80,19 @@ struct _GArchInstruction GArchInstruction **from; /* Origines des références */ InstructionLinkType *from_types; /* Type des liens de dest. */ size_t from_count; /* Nombre de ces origines */ + GRWLock from_access; /* Verrou de protection */ +#ifndef NDEBUG + gint hold_from_access; /* Suivi des verrouillages */ +#endif + GArchInstruction **to; /* Eventuelles lignes visées */ InstructionLinkType *to_types; /* Type des liens de dest. */ link_extra_info *links_info; /* Informations complémentaires*/ size_t to_count; /* Nombre de ces destinations */ + GRWLock to_access; /* Verrou de protection */ +#ifndef NDEBUG + gint hold_to_access; /* Suivi des verrouillages */ +#endif get_instruction_rw_regs_fc get_rw_regs; /* Liste des registres liés */ //print_instruction_fc print; /* Imprime l'ensemble */ @@ -91,7 +100,7 @@ struct _GArchInstruction //is_instruction_return_fc is_return; /* Retour de fonction ou pas ? */ decomp_instr_fc decomp; /* Procédure de décompilation */ - bool is_return; /* Retour de fonction ou pas ? */ + bool is_return; /* Retour de fonction ou pas ? */ // FIXME : à virer }; diff --git a/src/arch/instruction.c b/src/arch/instruction.c index 46f533e..4de70b7 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -107,6 +107,12 @@ static void g_arch_instruction_init(GArchInstruction *instr) instr->is_return = false; + g_rw_lock_init(&instr->from_access); + g_atomic_int_set(&instr->hold_from_access, 0); + + g_rw_lock_init(&instr->to_access); + g_atomic_int_set(&instr->hold_to_access, 0); + } @@ -143,6 +149,9 @@ static void g_arch_instruction_dispose(GArchInstruction *instr) static void g_arch_instruction_finalize(GArchInstruction *instr) { + g_rw_lock_clear(&instr->from_access); + g_rw_lock_clear(&instr->to_access); + G_OBJECT_CLASS(g_arch_instruction_parent_class)->finalize(G_OBJECT(instr)); } @@ -558,6 +567,8 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des /* Côté destination */ + g_arch_instruction_wlock_src(dest); + count = ++dest->from_count; dest->from = (GArchInstruction **)realloc(dest->from, @@ -568,8 +579,12 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des dest->from[count - 1] = instr; dest->from_types[count - 1] = type; + g_arch_instruction_wunlock_src(dest); + /* Côté point de départ */ + g_arch_instruction_wlock_dest(instr); + count = ++instr->to_count; instr->to = (GArchInstruction **)realloc(instr->to, @@ -595,6 +610,8 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des va_end(ap); + g_arch_instruction_wunlock_dest(instr); + } @@ -609,17 +626,24 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des * * * Retour : true pour une mise à jour réussie, false sinon. * * * -* Remarques : - * +* Remarques : Le verrou doit être posé sur les destination de 'instr'. * * * ******************************************************************************/ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType old, InstructionLinkType new) { + bool result; /* Bilan à retourner */ size_t count; /* Raccourci pour la lecture */ size_t i; /* Boucle de parcours */ size_t from_idx; /* Indice côté destination */ size_t to_idx; /* Indice côté source */ + result = false; + + assert(g_atomic_int_get(&instr->hold_to_access) > 0); + + g_arch_instruction_wlock_src(dest); + /* Côté destination */ count = dest->from_count; @@ -629,7 +653,7 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d break; if (i == count) - return false; + goto gaicl_exit; else from_idx = i; @@ -642,7 +666,7 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d break; if (i == count) - return false; + goto gaicl_exit; else to_idx = i; @@ -652,7 +676,13 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d instr->to_types[to_idx] = new; - return true; + result = true; + + gaicl_exit: + + g_arch_instruction_wunlock_src(dest); + + return result; /* TODO : si les informations complémentaires restent en place, compléter ! */ @@ -662,6 +692,46 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d /****************************************************************************** * * +* Paramètres : collec = collection à mettre à jour. * +* write = précise le type d'accès prévu (lecture/écriture). * +* lock = indique le sens du verrouillage à mener. * +* * +* Description : Met à disposition un encadrement des accès aux sources. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_arch_instruction_lock_unlock_sources(GArchInstruction *instr, bool write, bool lock) +{ +#ifndef NDEBUG + if (!lock) + g_atomic_int_dec_and_test(&instr->hold_from_access); +#endif + + if (write) + { + if (lock) g_rw_lock_writer_lock(&instr->from_access); + else g_rw_lock_writer_unlock(&instr->from_access); + } + else + { + if (lock) g_rw_lock_reader_lock(&instr->from_access); + else g_rw_lock_reader_unlock(&instr->from_access); + } + +#ifndef NDEBUG + if (lock) + g_atomic_int_inc(&instr->hold_from_access); +#endif + +} + + +/****************************************************************************** +* * * Paramètres : instr = instruction dont les informations sont à consulter. * * * * Description : Indique si l'instruction a une ou plusieurs origines. * @@ -674,6 +744,8 @@ bool g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *d bool g_arch_instruction_has_sources(const GArchInstruction *instr) { + assert(g_atomic_int_get(&instr->hold_from_access) > 0); + return (instr->from_count > 0); } @@ -695,6 +767,8 @@ bool g_arch_instruction_has_sources(const GArchInstruction *instr) size_t g_arch_instruction_get_sources(const GArchInstruction *instr, GArchInstruction ***srcs, InstructionLinkType **types) { + assert(g_atomic_int_get(&instr->hold_from_access) > 0); + if (srcs != NULL) *srcs = instr->from; @@ -708,6 +782,46 @@ size_t g_arch_instruction_get_sources(const GArchInstruction *instr, GArchInstru /****************************************************************************** * * +* Paramètres : collec = collection à mettre à jour. * +* write = précise le type d'accès prévu (lecture/écriture). * +* lock = indique le sens du verrouillage à mener. * +* * +* Description : Met à disposition un encadrement des accès aux destinations. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_arch_instruction_lock_unlock_destinations(GArchInstruction *instr, bool write, bool lock) +{ +#ifndef NDEBUG + if (!lock) + g_atomic_int_dec_and_test(&instr->hold_to_access); +#endif + + if (write) + { + if (lock) g_rw_lock_writer_lock(&instr->to_access); + else g_rw_lock_writer_unlock(&instr->to_access); + } + else + { + if (lock) g_rw_lock_reader_lock(&instr->to_access); + else g_rw_lock_reader_unlock(&instr->to_access); + } + +#ifndef NDEBUG + if (lock) + g_atomic_int_inc(&instr->hold_to_access); +#endif + +} + + +/****************************************************************************** +* * * Paramètres : instr = instruction dont les informations sont à consulter. * * * * Description : Indique si l'instruction a une suite autre que la suivante. * @@ -720,8 +834,8 @@ size_t g_arch_instruction_get_sources(const GArchInstruction *instr, GArchInstru bool g_arch_instruction_has_destinations(const GArchInstruction *instr) { - /* FIXME !? */ - //return (instr->to_count > 1 || (instr->to_count == 1 && instr->to_types[0] != ILT_CALL)); + assert(g_atomic_int_get(&instr->hold_to_access) > 0); + return (instr->to_count > 0); } @@ -744,6 +858,8 @@ bool g_arch_instruction_has_destinations(const GArchInstruction *instr) size_t g_arch_instruction_get_destinations(const GArchInstruction *instr, GArchInstruction ***dests, InstructionLinkType **types, link_extra_info **info) { + assert(g_atomic_int_get(&instr->hold_to_access) > 0); + if (dests != NULL) *dests = instr->to; @@ -778,6 +894,8 @@ GArchInstruction *g_arch_instruction_get_given_destination(const GArchInstructio result = NULL; + assert(g_atomic_int_get(&instr->hold_to_access) > 0); + for (i = 0; i < instr->to_count && result == NULL; i++) if (instr->to_types[i] == type) result = instr->to[i]; diff --git a/src/arch/instruction.h b/src/arch/instruction.h index 95d2e22..f26a240 100644 --- a/src/arch/instruction.h +++ b/src/arch/instruction.h @@ -189,12 +189,30 @@ void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, Instru /* Change la nature d'un lien entre deux instructions. */ bool g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, InstructionLinkType, InstructionLinkType); +/* Met à disposition un encadrement des accès aux sources. */ +void g_arch_instruction_lock_unlock_sources(GArchInstruction *, bool, bool); + +#define g_arch_instruction_wlock_src(ins) g_arch_instruction_lock_unlock_sources(ins, true, true) +#define g_arch_instruction_wunlock_src(ins) g_arch_instruction_lock_unlock_sources(ins, true, false) + +#define g_arch_instruction_rlock_src(ins) g_arch_instruction_lock_unlock_sources(ins, false, true) +#define g_arch_instruction_runlock_src(ins) g_arch_instruction_lock_unlock_sources(ins, false, false) + /* Indique si l'instruction a une ou plusieurs origines. */ bool g_arch_instruction_has_sources(const GArchInstruction *); /* Fournit les origines d'une instruction donnée. */ size_t g_arch_instruction_get_sources(const GArchInstruction *, GArchInstruction ***, InstructionLinkType **); +/* Met à disposition un encadrement des accès aux destinations. */ +void g_arch_instruction_lock_unlock_destinations(GArchInstruction *, bool, bool); + +#define g_arch_instruction_wlock_dest(ins) g_arch_instruction_lock_unlock_destinations(ins, true, true) +#define g_arch_instruction_wunlock_dest(ins) g_arch_instruction_lock_unlock_destinations(ins, true, false) + +#define g_arch_instruction_rlock_dest(ins) g_arch_instruction_lock_unlock_destinations(ins, false, true) +#define g_arch_instruction_runlock_dest(ins) g_arch_instruction_lock_unlock_destinations(ins, false, false) + /* Indique si l'instruction a une suite autre que la suivante. */ bool g_arch_instruction_has_destinations(const GArchInstruction *); diff --git a/src/gtkext/graph/nodes/flow.c b/src/gtkext/graph/nodes/flow.c index 343f916..e19cacb 100644 --- a/src/gtkext/graph/nodes/flow.c +++ b/src/gtkext/graph/nodes/flow.c @@ -827,6 +827,8 @@ static void g_flow_node_setup_entry_slots(GFlowNode *node) size_t used; /* Nombre de liens utilisés */ g_flow_block_get_boundary(node->block, &first, NULL); + + g_arch_instruction_rlock_src(first); icount = g_arch_instruction_get_sources(first, &instrs, &types); usable = 0; @@ -892,6 +894,8 @@ static void g_flow_node_setup_entry_slots(GFlowNode *node) assert(used == usable); + g_arch_instruction_runlock_src(first); + } @@ -918,6 +922,8 @@ static void g_flow_node_setup_exit_slots(GFlowNode *node) size_t used; /* Nombre de liens utilisés */ g_flow_block_get_boundary(node->block, NULL, &last); + + g_arch_instruction_rlock_dest(last); icount = g_arch_instruction_get_destinations(last, &instrs, &types, NULL); usable = 0; @@ -983,6 +989,8 @@ static void g_flow_node_setup_exit_slots(GFlowNode *node) assert(used == usable); + g_arch_instruction_runlock_dest(last); + } diff --git a/src/gui/dialogs/gotox.c b/src/gui/dialogs/gotox.c index fd05100..5d19fee 100644 --- a/src/gui/dialogs/gotox.c +++ b/src/gui/dialogs/gotox.c @@ -269,7 +269,7 @@ GtkWidget *create_gotox_dialog_for_entry_points(GtkWindow *parent, GLoadedBinary * * ******************************************************************************/ -GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *parent, GLoadedBinary *binary, const GArchInstruction *instr, bool back) +GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *parent, GLoadedBinary *binary, GArchInstruction *instr, bool back) { GtkWidget *result; /* Fenêtre à renvoyer */ GtkTreeStore *store; /* Modèle de gestion */ @@ -290,9 +290,15 @@ GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *parent, GLoadedBi /* Affichage de toutes les instructions référencées */ if (back) + { + g_arch_instruction_rlock_src(instr); count = g_arch_instruction_get_sources(instr, &list, NULL); + } else + { + g_arch_instruction_rlock_dest(instr); count = g_arch_instruction_get_destinations(instr, &list, NULL, NULL); + } for (i = 0; i < count; i++) { @@ -302,6 +308,11 @@ GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *parent, GLoadedBi } + if (back) + g_arch_instruction_runlock_src(instr); + else + g_arch_instruction_runlock_dest(instr); + g_object_unref(G_OBJECT(store)); gtk_dialog_set_response_sensitive(GTK_DIALOG(result), GTK_RESPONSE_OK, count > 0); diff --git a/src/gui/dialogs/gotox.h b/src/gui/dialogs/gotox.h index ab17d42..4284ae8 100644 --- a/src/gui/dialogs/gotox.h +++ b/src/gui/dialogs/gotox.h @@ -37,7 +37,7 @@ GtkWidget *create_gotox_dialog_for_entry_points(GtkWindow *, GLoadedBinary *); /* Construit la fenêtre de sélection des références croisées. */ -GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *, GLoadedBinary *, const GArchInstruction *, bool); +GtkWidget *create_gotox_dialog_for_cross_references(GtkWindow *, GLoadedBinary *, GArchInstruction *, bool); /* Fournit l'adresse obtenue par la saisie de l'utilisateur. */ vmpa2t *get_address_from_gotox_dialog(GtkWidget *); -- cgit v0.11.2-87-g4458