From e5e7408e52f33039db6315f82b294e604503ad78 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 28 Jan 2017 00:07:27 +0100
Subject: Established natural links between instructions only when relevant.

---
 ChangeLog                   |  5 +++
 src/analysis/disass/links.c | 85 ++++++++++++++++++++++++++++++++++-----------
 2 files changed, 69 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index bd3d98f..bfaf59a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+17-01-28  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/analysis/disass/links.c:
+	Establish natural links between instructions only when relevant.
+
 17-01-27  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gtkext/easygtk.c:
diff --git a/src/analysis/disass/links.c b/src/analysis/disass/links.c
index d3434cb..0884dce 100644
--- a/src/analysis/disass/links.c
+++ b/src/analysis/disass/links.c
@@ -24,6 +24,8 @@
 #include "links.h"
 
 
+#include <assert.h>
+
 
 #include "../../arch/instruction.h"
 #include "../../arch/raw.h"
@@ -52,6 +54,8 @@ static void convert_immediate_into_target(GArchInstruction *, size_t, GBinFormat
 void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
 {
     bool has_src;                           /* Présence de sources ?       */
+    bool no_natural;                        /* Aucun lien naturel présent  */
+    bool no_need;                           /* Pas de besoin pour ce lien  */
     instr_link_t *others;                   /* Instructions diverses liées */
     size_t count;                           /* Nbre de sources affichées   */
     size_t i;                               /* Boucle de parcours          */
@@ -80,42 +84,81 @@ void establish_natural_link(GArchInstruction *instr, GArchInstruction *prev)
         return;
 
     /**
-     * On s'assure que le lien naturel est valide.
+     * On s'assure que le lien naturel est nécessaire et qu'il n'est pas
+     * déjà en place.
      */
 
+    no_natural = true;
+    no_need = true;
+
     g_arch_instruction_rlock_dest(prev);
     count = g_arch_instruction_get_destinations(prev, &others);
 
-    for (i = 0; i < count; i++)
-    {
-        if (others[i].type == ILT_EXEC_FLOW) break;
-        if (others[i].type == ILT_JUMP) break;
-        if (others[i].type == ILT_CASE_JUMP) break;
-        if (others[i].type == ILT_LOOP) break;
-    }
+    for (i = 0; i < count && no_natural; i++)
+        switch (others[i].type)
+        {
+            case ILT_EXEC_FLOW:
+                no_natural = false;
+                break;
+
+            case ILT_JUMP_IF_TRUE:
+            case ILT_JUMP_IF_FALSE:
+                if (others[i].linked != instr)
+                    no_need = false;
+                else
+                {
+                    no_need = true;
+                    goto check_done;
+                }
+                break;
+
+            default:
+                break;
+
+        }
+
+ check_done:
 
     g_arch_instruction_runlock_dest(prev);
 
-    if (count > 0 && i < count) return;
+    if (no_natural && !no_need)
+    {
+        /* Vérification de la cohérence de l'ensemble */
+#ifndef NDEBUG
 
-    /**
-     * 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);
 
-    g_arch_instruction_rlock_src(instr);
-    count = g_arch_instruction_get_sources(instr, &others);
+        for (i = 0; i < count; i++)
+            switch (others[i].type)
+            {
+                case ILT_NONE:
+                case ILT_EXEC_FLOW:
+                    assert(false);
+                    break;
 
-    for (i = 0; i < count; i++)
-    {
-        if (others[i].linked == prev && others[i].type == ILT_JUMP_IF_TRUE) break;
-        if (others[i].linked == prev && others[i].type == ILT_JUMP_IF_FALSE) break;
-    }
+                case ILT_JUMP:
+                case ILT_CASE_JUMP:
+                case ILT_JUMP_IF_TRUE:
+                case ILT_JUMP_IF_FALSE:
+                case ILT_LOOP:
+                case ILT_CATCH_EXCEPTION:
+                    assert(others[i].linked != prev);
+                    break;
 
-    g_arch_instruction_runlock_src(instr);
+                default:
+                    break;
+
+            }
+
+        g_arch_instruction_runlock_src(instr);
+
+#endif
 
-    if (i == count)
         g_arch_instruction_link_with(prev, instr, ILT_EXEC_FLOW);
 
+    }
+
 }
 
 
-- 
cgit v0.11.2-87-g4458