From 40d624af29e752bb4255099ab3f1de64e3c96dd3 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 5 Apr 2015 23:12:13 +0000 Subject: Fixed various bugs in the graph layout. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@504 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 21 ++++++++ src/analysis/disass/loop.c | 2 +- src/arch/instruction.c | 62 +++++++++++++++++++++++ src/arch/instruction.h | 3 ++ src/gtkext/graph/edge.c | 2 +- src/gtkext/graph/node.c | 9 ++++ src/gtkext/graph/nodes/flow.c | 46 +++++++++++++---- src/gtkext/graph/nodes/virtual.c | 106 +++------------------------------------ 8 files changed, 142 insertions(+), 109 deletions(-) diff --git a/ChangeLog b/ChangeLog index ab7eb20..2660ff1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +15-04-06 Cyrille Bagard + + * src/analysis/disass/loop.c: + Update code when creating loops. + + * src/arch/instruction.c: + * src/arch/instruction.h: + Provide a way to properly change an existing link between instructions. + + * src/gtkext/graph/edge.c: + Change the direction for looping edges to left. + + * src/gtkext/graph/node.c: + Upgrade code. Set a pending position only one time. + + * src/gtkext/graph/nodes/flow.c: + Align vertical edges when there is a loop edge in the final block entries. + + * src/gtkext/graph/nodes/virtual.c: + Fix the position of loop edges. + 15-04-05 Cyrille Bagard * src/gtkext/graph/layout.c: diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c index 0cb346b..44fa6d5 100644 --- a/src/analysis/disass/loop.c +++ b/src/analysis/disass/loop.c @@ -269,7 +269,7 @@ static void track_loops_in_code(const GArchProcessor *proc, const mrange_t *rang addr = get_mrange_addr(irange); if (!is_new_exec_flow(flow, addr)) - types[i] = ILT_LOOP; + /* status = */g_arch_instruction_change_link(iter, dests[i], types[i], ILT_LOOP); else { diff --git a/src/arch/instruction.c b/src/arch/instruction.c index 08256d1..475c038 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -624,6 +624,68 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des /****************************************************************************** * * * Paramètres : instr = instruction dont les informations sont à consulter. * +* dest = ligne visée par la liaison (côté destination). * +* old = ancien type de lien construit. * +* new = nouveau type de lien à construire. * +* * +* Description : Change la nature d'un lien entre deux instructions. * +* * +* Retour : true pour une mise à jour réussie, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_arch_instruction_change_link(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType old, InstructionLinkType new) +{ + 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 */ + + /* Côté destination */ + + count = dest->from_count; + + for (i = 0; i < count; i++) + if (dest->from[i] == instr && dest->from_types[i] == old) + break; + + if (i == count) + return false; + else + from_idx = i; + + /* Côté point de départ */ + + count = instr->to_count; + + for (i = 0; i < count; i++) + if (instr->to[i] == dest && instr->to_types[i] == old) + break; + + if (i == count) + return false; + else + to_idx = i; + + /* Si les deux extrémités sont raccord... */ + + dest->from_types[from_idx] = new; + + instr->to_types[to_idx] = new; + + return true; + + + /* TODO : si les informations complémentaires restent en place, compléter ! */ + +} + + +/****************************************************************************** +* * +* Paramètres : instr = instruction dont les informations sont à consulter. * * * * Description : Indique si l'instruction a une ou plusieurs origines. * * * diff --git a/src/arch/instruction.h b/src/arch/instruction.h index 0198bb5..9123b6f 100644 --- a/src/arch/instruction.h +++ b/src/arch/instruction.h @@ -188,6 +188,9 @@ bool g_arch_instruction_is_return(const GArchInstruction *instr); /* Etablit un lien entre deux instructions. */ void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, InstructionLinkType, ...); +/* Change la nature d'un lien entre deux instructions. */ +void g_arch_instruction_change_link(GArchInstruction *, GArchInstruction *, InstructionLinkType, InstructionLinkType); + /* Indique si l'instruction a une ou plusieurs origines. */ bool g_arch_instruction_has_sources(const GArchInstruction *); diff --git a/src/gtkext/graph/edge.c b/src/gtkext/graph/edge.c index cd312cb..acd164c 100644 --- a/src/gtkext/graph/edge.c +++ b/src/gtkext/graph/edge.c @@ -238,7 +238,7 @@ void g_graph_edge_reserve_vertical_space(GGraphEdge *edge, GGraphNode *nodes, GG g_object_ref(G_OBJECT(container)); edge->container = G_VIRTUAL_NODE(container); - edge->is_left = false; /* TODO */ + edge->is_left = true; /* TODO */ r1 = g_graph_node_get_rank(G_GRAPH_NODE(edge->src_node)); r2 = g_graph_node_get_rank(G_GRAPH_NODE(edge->dest_node)); diff --git a/src/gtkext/graph/node.c b/src/gtkext/graph/node.c index 3801d1a..ec09941 100644 --- a/src/gtkext/graph/node.c +++ b/src/gtkext/graph/node.c @@ -24,6 +24,7 @@ #include "node.h" +#include #include #include #include @@ -258,6 +259,8 @@ void g_graph_node_reset_position(GGraphNode *node) node->alloc.x = UNINITIALIZED_NODE_POS; node->alloc.y = UNINITIALIZED_NODE_POS; + node->pending_flag = PPF_NONE; + if (node->reset_pos != NULL) node->reset_pos(node); @@ -307,18 +310,21 @@ void g_graph_node_apply_position(GGraphNode *node) switch (node->pending_flag) { case PPF_DIRECT_X: + assert(g_graph_node_has_x_position(node->pending_rel)); g_graph_node_get_position(node->pending_rel, &x_pos, NULL); x_pos += node->pending_pos.direct_x; g_graph_node_set_x_position(node, x_pos); break; case PPF_LEFT_MARGIN: + assert(g_graph_node_has_x_position(node->pending_rel)); g_graph_node_get_position(node->pending_rel, &x_pos, NULL); x_pos += EDGE_SLOT_HORIZ_MARGIN + node->pending_pos.left_margin; g_graph_node_set_x_position(node, x_pos); break; case PPF_RIGHT_MARGIN: + assert(g_graph_node_has_x_position(node->pending_rel)); g_graph_node_get_position(node->pending_rel, &x_pos, NULL); x_pos += node->pending_pos.right_margin; x_pos -= (EDGE_SLOT_HORIZ_MARGIN + node->alloc.width); @@ -386,6 +392,9 @@ void g_graph_node_set_x_position(GGraphNode *node, gint x) void g_graph_node_set_pending_position(GGraphNode *node, PendingPositionFlags flag, pending_position pos, GGraphNode *rel) { + if (node->pending_flag != PPF_NONE) + return; + node->pending_pos = pos; node->pending_flag = flag; node->pending_rel = rel; diff --git a/src/gtkext/graph/nodes/flow.c b/src/gtkext/graph/nodes/flow.c index 5173810..863d86c 100644 --- a/src/gtkext/graph/nodes/flow.c +++ b/src/gtkext/graph/nodes/flow.c @@ -299,6 +299,7 @@ static void g_flow_node_prepare_x_line(GFlowNode *node, GGraphNode *nodes) { GGraphNode *base; /* Autre vision de l'instance */ GArchInstruction *last; /* Dernière instr. du noeud */ + size_t loop_index; /* Indice de sortie en boucle */ GFlowNode *target; /* Bloc visé par le lien */ node_slot_t *dest_slot; /* Accrochage d'arrivée */ pending_position pos; /* Position à transmettre */ @@ -312,25 +313,52 @@ static void g_flow_node_prepare_x_line(GFlowNode *node, GGraphNode *nodes) g_flow_block_get_boundary(node->block, NULL, &last); - switch (node->exits_count) + for (loop_index = 0; loop_index < node->exits_count; loop_index++) + if (node->exits[loop_index].type == ILT_LOOP) + break; + + switch (node->exits_count - (loop_index == node->exits_count ? 0 : 1)) { case 0: break; case 1: - if (node->exits[0].type == ILT_LOOP) - break; + if (loop_index == node->exits_count) + { + target = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[0].instr)); + + dest_slot = g_flow_node_get_slot(target, true, + last, node->exits[0].group_index); - target = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[0].instr)); + } + else + { + target = G_FLOW_NODE(find_node_for_instruction(nodes, node->exits[1].instr)); - dest_slot = g_flow_node_get_slot(target, true, - last, node->exits[0].group_index); + dest_slot = g_flow_node_get_slot(target, true, + last, node->exits[1].group_index); + + } pos.direct_x = g_flow_node_get_slot_offset(target, true, dest_slot); pos.direct_x = (G_GRAPH_NODE(target)->alloc.width / 2) - pos.direct_x; - if (target->entries_count == 1) + pos.direct_x -= (G_GRAPH_NODE(target)->alloc.width - G_GRAPH_NODE(node)->alloc.width) / 2; + + size_t count_and_skip_loop(GFlowNode *n) + { + size_t counter; + + for (counter = 0; counter < n->entries_count; counter++) + if (n->entries[counter].type == ILT_LOOP) + break; + + return counter < n->entries_count ? n->entries_count - 1 : n->entries_count; + + } + + if (count_and_skip_loop(target) == 1) g_graph_node_set_pending_position(G_GRAPH_NODE(target), PPF_DIRECT_X, pos, base); break; @@ -678,7 +706,7 @@ static void g_flow_node_setup_entry_slots(GFlowNode *node) node->entries[used].type = types[i]; node->entries[used].group_index = g_arch_instruction_compute_group_index(&instrs[i], - instrs, icount); + instrs, icount); node->entries[used].slot_index = i; used++; @@ -769,7 +797,7 @@ static void g_flow_node_setup_exit_slots(GFlowNode *node) node->exits[used].type = types[i]; node->exits[used].group_index = g_arch_instruction_compute_group_index(&instrs[i], - instrs, icount); + instrs, icount); node->exits[used].slot_index = i; used++; diff --git a/src/gtkext/graph/nodes/virtual.c b/src/gtkext/graph/nodes/virtual.c index e04ff5d..cb46aee 100644 --- a/src/gtkext/graph/nodes/virtual.c +++ b/src/gtkext/graph/nodes/virtual.c @@ -24,6 +24,7 @@ #include "virtual.h" +#include #include #include @@ -365,7 +366,6 @@ static void g_virtual_node_finalize(GVirtualNode *node) /****************************************************************************** * * * Paramètres : block = bloc virtuel représenté graphiquement. * -* view = morceau d'affichage à représenter. * * * * Description : Encapsule graphiquement un bloc virtuel. * * * @@ -489,12 +489,14 @@ static void g_virtual_node_apply_position(GVirtualNode *node) } /* Espace pour les liens remontants */ + if (node->left_count > 0) offset = EDGE_SLOT_HORIZ_MARGIN + EDGE_HORIZONTAL_MIN_SEP * (node->left_count - 1); else offset = 0; /* Ajout du décallage le plus grand */ + offset += -min; /* Traitement des sous-noeuds */ @@ -543,14 +545,14 @@ static void g_virtual_node_apply_x_line(GVirtualNode *node) { level = &node->levels[i]; - /* Si l'ensemble de l'étage doit être aligné */ + /* Si l'ensemble de l'étage doit être centré */ if (level->children[0]->pending_flag == PPF_NONE) { width_sum = 0; for (j = 0; j < level->count; j++) { - /* BUG_ON(level->children[j]->pending_flag != PPF_NONE); */ + assert(level->children[j]->pending_flag == PPF_NONE); g_graph_node_apply_position(level->children[j]); width_sum += level->children[j]->alloc.width; @@ -698,98 +700,6 @@ static void g_virtual_node_set_position(GVirtualNode *node, gint x) /****************************************************************************** * * -* Paramètres : node = noeud graphique à consulter. * -* * -* Description : Indique l'espace requis pour un noeud d'encapsulation. * -* * -* Retour : Espace constitué, entièrement ou non. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GtkAllocation g_virtual_node_get_allocation(const GVirtualNode *node) -{ - GtkAllocation result; /* Valeurs à retourner */ - gint margins; /* Bordures gauche et droite */ - unsigned int last_rank; /* Détection de saut de rangs */ - size_t vert_count; /* Quantité à la verticale */ - gint rank_width; /* Largeur d'un rang donné */ - gint rank_height; /* Hauteur d'un rang donné */ - size_t i; /* Boucle de parcours */ - GtkAllocation alloc; /* Allocation d'un sous-noeud */ - - result.x = node->x; - result.y = node->y; - - result.width = 0; - margins = 0; - if (node->left_count > 0) - { - margins += EDGE_SLOT_HORIZ_MARGIN; - margins += (node->left_count - 1) * EDGE_HORIZONTAL_MIN_SEP; - } - if (node->right_count > 0) - { - margins += EDGE_SLOT_HORIZ_MARGIN; - margins += (node->right_count - 1) * EDGE_HORIZONTAL_MIN_SEP; - } - result.height = 0; - - last_rank = -1; - - vert_count = 0; - - rank_width = 0; - rank_height = 0; - - for (i = 0; i < node->count; i++) - { - alloc = g_graph_node_get_allocation(node->children[i]); - - /* Prise en compte de l'étage précédent */ - if (last_rank != g_graph_node_get_rank(node->children[i])) - { - last_rank = g_graph_node_get_rank(node->children[i]); - - result.width = MAX(result.width, rank_width); - result.height += rank_height; - - rank_width = 0; - rank_height = 0; - - vert_count++; - - } - - /* Mise à jour de l'étage courant */ - - if (node->x == UNINITIALIZED_NODE_POS) - { - rank_width += alloc.width; - if (rank_width > 0) rank_width += NODE_LEFT_MARGIN; - } - else - rank_width = MAX(alloc.x + alloc.width - node->x, rank_width); - - rank_height = MAX(rank_height, alloc.height); - - } - - result.width = MAX(result.width, rank_width); - - result.width += margins; - - if (vert_count > 1) - result.height += (vert_count - 1) * NODE_TOP_MARGIN; - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : node = noeud graphique démarrant la visite. * * callback = ensemble de blocs à parcourir. * * data = donnée utilisateur à associer au parcours. * @@ -1026,14 +936,14 @@ gint g_virtual_node_get_x_for_vspan_slot(const GVirtualNode *node, vspan_slot_t gint result; /* Position à retourner */ GtkAllocation alloc; /* Taille totale requise */ - alloc = g_virtual_node_get_allocation(node); + alloc = G_GRAPH_NODE(node)->alloc; if (left) { /*BUG_ON(slot >= node->left_count) */ - result = (node->left_count - 1) * EDGE_HORIZONTAL_MIN_SEP/* + EDGE_SLOT_HORIZ_MARGIN*/; - result -= (slot * EDGE_HORIZONTAL_MIN_SEP/* + EDGE_SLOT_HORIZ_MARGIN*/); + result = -(node->left_count - 1) * EDGE_HORIZONTAL_MIN_SEP/* + EDGE_SLOT_HORIZ_MARGIN*/; + result += (slot * EDGE_HORIZONTAL_MIN_SEP/* + EDGE_SLOT_HORIZ_MARGIN*/); result += alloc.x; -- cgit v0.11.2-87-g4458