From 0936f64aac6a4fa9ebc08962bc9cac663f210c00 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Thu, 31 Jan 2013 21:29:49 +0000
Subject: Saved the first steps of switch instructions decompilation.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@335 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                          |  50 +++++
 plugins/androhelpers/switch.c      |  16 +-
 src/analysis/blocks/flow.c         |   2 +-
 src/analysis/decomp/il.c           |  51 ++++-
 src/analysis/disass/macro.c        |  14 +-
 src/arch/dalvik/decomp/Makefile.am |   1 +
 src/arch/dalvik/decomp/if.c        |   8 +-
 src/arch/dalvik/decomp/switch.c    |  62 ++++++
 src/arch/dalvik/decomp/translate.h |   7 +-
 src/arch/dalvik/instruction.c      |   4 +-
 src/arch/dalvik/opcodes/switch.c   |   2 +-
 src/arch/instruction-int.h         |   1 +
 src/arch/instruction.c             |  32 +++-
 src/arch/instruction.h             |  48 +++--
 src/decomp/expr/immediate.c        |   2 +-
 src/decomp/instr/Makefile.am       |   3 +-
 src/decomp/instr/ite.c             |  46 ++---
 src/decomp/instr/ite.h             |  16 +-
 src/decomp/instr/switch.c          | 379 +++++++++++++++++++++++++++++++++++++
 src/decomp/instr/switch.h          |  66 +++++++
 src/gtkext/graph/layout.c          |   2 +-
 21 files changed, 733 insertions(+), 79 deletions(-)
 create mode 100644 src/arch/dalvik/decomp/switch.c
 create mode 100644 src/decomp/instr/switch.c
 create mode 100644 src/decomp/instr/switch.h

diff --git a/ChangeLog b/ChangeLog
index 167da05..6c9b261 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+13-01-31  Cyrille Bagard <nocbos@gmail.com>
+
+	* plugins/androhelpers/switch.c:
+	Store the case value with the link of each switch case.
+
+	* src/analysis/blocks/flow.c:
+	Update code.
+
+	* src/analysis/decomp/il.c:
+	Save the first steps of switch instructions decompilation.
+
+	* src/analysis/disass/macro.c:
+	Update code.
+
+	* src/arch/dalvik/decomp/if.c:
+	Typo.
+
+	* src/arch/dalvik/decomp/Makefile.am:
+	Add the 'switch.[ch]' files to libarchdalvikdecomp_la_SOURCES.
+
+	* src/arch/dalvik/decomp/switch.c:
+	* src/arch/dalvik/decomp/translate.h:
+	* src/arch/dalvik/instruction.c:
+	Decompile Dalvik switch instructions.
+
+	* src/arch/dalvik/opcodes/switch.c:
+	Typo.
+
+	* src/arch/instruction.c:
+	* src/arch/instruction.h:
+	* src/arch/instruction-int.h:
+	Store extra information with links between instructions.
+
+	* src/decomp/expr/immediate.c:
+	Add a note for later.
+
+	* src/decomp/instr/ite.c:
+	* src/decomp/instr/ite.h:
+	Typo.
+
+	* src/decomp/instr/Makefile.am:
+	Add the 'switch.[ch]' files to libdecompinstr_la_SOURCES.
+
+	* src/decomp/instr/switch.c:
+	* src/decomp/instr/switch.h:
+	New entries: decompile switch instructions.
+
+	* src/gtkext/graph/layout.c:
+	Update code.
+
 13-01-28  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gui/panels/glance.c:
diff --git a/plugins/androhelpers/switch.c b/plugins/androhelpers/switch.c
index 9e6f306..0a1e488 100644
--- a/plugins/androhelpers/switch.c
+++ b/plugins/androhelpers/switch.c
@@ -27,6 +27,7 @@
 #include <string.h>
 
 
+#include <arch/immediate.h>
 #include <arch/dalvik/instruction.h>
 #include <arch/dalvik/instruction-def.h>
 #include <arch/dalvik/operands/target.h>
@@ -139,6 +140,8 @@ static void link_all_switch_cases(GArchInstruction *instr, const dex_switch *dsw
     uint32_t *targets;                      /* Cibles relatives à corriger */
     uint16_t i;                             /* Boucle de parcours          */
     GArchInstruction *next;                 /* Instruction suivante        */
+    uint32_t value;                         /* Valeur à indiquer           */
+    GArchOperand *imm;                      /* Forme de la valeur reconnue */
 
     /* Valeurs définies */
 
@@ -155,7 +158,16 @@ static void link_all_switch_cases(GArchInstruction *instr, const dex_switch *dsw
         next = g_arch_instruction_find_by_address(instrs, (vmpa_t)targets[i], true);
 
         if (next != NULL)
-            g_arch_instruction_link_with(instr, next, ILT_CASE_JUMP);
+        {
+            if (dswitch->packed.ident == DPO_PACKED_SWITCH)
+                value = dswitch->packed.first_key + i;
+            else
+                value = dswitch->sparse.keys[i];
+
+            imm = g_imm_operand_new_from_value(MDS_32_BITS_UNSIGNED, value);
+            g_arch_instruction_link_with(instr, next, ILT_CASE_JUMP, imm);
+
+        }
 
     }
 
@@ -164,7 +176,7 @@ static void link_all_switch_cases(GArchInstruction *instr, const dex_switch *dsw
     next = g_arch_instruction_get_next_iter(instrs, instr, end);
 
     if (next != NULL)
-        g_arch_instruction_link_with(instr, next, ILT_CASE_JUMP);
+        g_arch_instruction_link_with(instr, next, ILT_CASE_JUMP, NULL);
 
 }
 
diff --git a/src/analysis/blocks/flow.c b/src/analysis/blocks/flow.c
index 49b9c6b..4df729c 100644
--- a/src/analysis/blocks/flow.c
+++ b/src/analysis/blocks/flow.c
@@ -510,7 +510,7 @@ bool g_flow_block_follow(GFlowBlock *block, const GInstrBlock *list, BlockFollow
     if (mask & BFP_ENTER)
         result = callback(block, BFP_ENTER, data);
 
-    dcount = g_arch_instruction_get_destinations(block->last, &dests, &types);
+    dcount = g_arch_instruction_get_destinations(block->last, &dests, &types, NULL);
 
     for (i = 0; i < dcount && result; i++)
         switch (types[i])
diff --git a/src/analysis/decomp/il.c b/src/analysis/decomp/il.c
index 64f6398..f241e46 100644
--- a/src/analysis/decomp/il.c
+++ b/src/analysis/decomp/il.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * il.h - mise en place d'un langage intermédiaire
  *
- * Copyright (C) 2012 Cyrille Bagard
+ * Copyright (C) 2012-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -27,7 +27,9 @@
 #include "../blocks/flow.h"
 #include "../blocks/virtual.h"
 #include "../../decomp/expr/block.h"
+#include "../../decomp/expr/immediate.h"
 #include "../../decomp/instr/ite.h"
+#include "../../decomp/instr/switch.h"
 
 
 
@@ -328,7 +330,7 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon
     GArchInstruction *first;                /* Première instruction du lot */
     GArchInstruction *last;                 /* Dernière instruction du lot */
     vmpa_t max;                             /* Adresse de fin du bloc      */
-    GArchInstruction *iter;                 /* Boucle de parcours          */
+    GArchInstruction *iter;                 /* Boucle de parcours #1       */
     GDecInstruction *decomp;                /* Dernier résultat de décomp. */
     GInstrBlock *sub_parent;                /* Groupe des sous-branches    */
     GHashTable *sub_shared;                 /* Allocations communes        */
@@ -338,6 +340,12 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon
     GArchInstruction *next;                 /* Instruction de branchement  */
     vmpa_t next_addr;                       /* Adresse de cette instruct°  */
     GInstrBlock *next_block;                /* Sous-bloc basique direct    */
+    GArchInstruction **dests;               /* Instr. visée par une autre  */
+    link_extra_info *info;                  /* Compléments pour les liens  */
+    size_t dcount;                          /* Nombre de liens de dest.    */
+    size_t i;                               /* Boucle de parcours #2       */
+    GDecInstruction *case_dinstr;           /* Décompilation 'case'        */
+    GDecExpression *case_value;             /* Valeur d'aiguillage         */
 
     instrs = g_flow_block_get_all_instructions_list(block);
     g_flow_block_get_boundary(block, &first, &last);
@@ -406,6 +414,45 @@ static GDecInstruction *decompiled_instructions_block(GFlowBlock *block, GDecCon
 
     }
 
+    /* switch ... case ... */
+    else if (G_IS_SWITCH_INSTRUCTION(decomp))
+    {
+        sub_parent = g_instr_block_get_links_block(G_INSTR_BLOCK(block));
+        sub_shared = g_hash_table_new_full((GHashFunc)g_arch_register_hash,
+                                           (GEqualFunc)g_arch_register_equal,
+                                           g_object_unref, g_object_unref);
+
+        dcount = g_arch_instruction_get_destinations(last, &dests, NULL, &info);
+
+        for (i = 0; i < dcount; i++)
+        {
+            g_arch_instruction_get_location(dests[i], NULL, NULL, &next_addr);
+            next_block = g_instr_block_find_by_addr(sub_parent, next_addr, false);
+
+            if (next_block != NULL)
+            {
+                sub_ctx = create_new_context_for_sub_block(ctx, next_block, sub_shared);
+                case_dinstr = decompiled_basic_block(next_block, sub_ctx);
+                g_dec_context_spread_allocated_shared_regs(ctx, sub_ctx);
+                g_object_unref(G_OBJECT(sub_ctx));
+
+                if (info[i].imm != NULL)
+                {
+                    case_value = G_DEC_EXPRESSION(g_imm_expression_new(info[i].imm));
+                    g_switch_instruction_add_case(G_SWITCH_INSTRUCTION(decomp),
+                                                  case_value, case_dinstr, next_addr);
+                }
+                else g_switch_instruction_set_default_case(G_SWITCH_INSTRUCTION(decomp),
+                                                           case_dinstr);
+
+            }
+
+        }
+
+        g_hash_table_unref(sub_shared);
+
+    }
+
     /* Renvoi des instructions mises en place */
 
     return g_dec_context_get_decomp_instrs(ctx);
diff --git a/src/analysis/disass/macro.c b/src/analysis/disass/macro.c
index 0fef9a0..14dad95 100644
--- a/src/analysis/disass/macro.c
+++ b/src/analysis/disass/macro.c
@@ -150,7 +150,7 @@ static void find_next_jumps(GArchInstruction *instrs, vmpa_t start, vmpa_t end,
         if (!g_arch_instruction_has_destinations(iter))
             continue;
 
-        dcount = g_arch_instruction_get_destinations(iter, &dests, &types);
+        dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
 
         for (i = 0; i < dcount; i++)
             switch (types[i])
@@ -360,7 +360,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
 
         /* Adaptations en fonction du type de bifurcation */
 
-        dcount = g_arch_instruction_get_destinations(iter, &dests, &types);
+        dcount = g_arch_instruction_get_destinations(iter, &dests, &types, NULL);
 
         next_addr = 0;
         cases_branches = NULL;
@@ -439,20 +439,22 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
 
             DELAYED_BLOCK_ADDING(result, result_cached, block);
 
-            //printf(" --- cases --- start\n");
+            printf(" --- cases --- start\n");
 
             next_addr = compute_first_common_addr_in_group(cases_branches, cases_count);
-            //printf("    stop :: 0x%08llx\n", next_addr);
+            printf("    stop :: 0x%08llx\n", next_addr);
 
             parent = block;
             group = g_virtual_block_new();
 
             for (j = 0; j < cases_count; j++)
             {
-                //printf(" ## %zu\n", j);
+                printf(" ## %zu...", j);
 
                 block = build_instruction_block(instrs, cases_branches[j].jumps[0], end, next_addr);
 
+                printf(" %p\n", block);
+
                 if (block != NULL)
 
                 g_virtual_block_add_child(G_VIRTUAL_BLOCK(group), block);
@@ -469,7 +471,7 @@ static GInstrBlock *build_instruction_block(GArchInstruction *instrs, vmpa_t sta
             else
                 g_object_unref(G_OBJECT(group));
 
-            //printf(" --- cases --- end\n");
+            printf(" --- cases --- end\n");
 
 
             free(cases_branches);
diff --git a/src/arch/dalvik/decomp/Makefile.am b/src/arch/dalvik/decomp/Makefile.am
index 7a7f068..3a0a197 100644
--- a/src/arch/dalvik/decomp/Makefile.am
+++ b/src/arch/dalvik/decomp/Makefile.am
@@ -14,6 +14,7 @@ libarchdalvikdecomp_la_SOURCES =		\
 	move.c								\
 	new.c								\
 	ret.c								\
+	switch.h switch.c					\
 	translate.h
 
 libarchdalvikdecomp_la_LIBADD =
diff --git a/src/arch/dalvik/decomp/if.c b/src/arch/dalvik/decomp/if.c
index 6a156ec..93e21d9 100644
--- a/src/arch/dalvik/decomp/if.c
+++ b/src/arch/dalvik/decomp/if.c
@@ -1,8 +1,8 @@
 
 /* OpenIDA - Outil d'analyse de fichiers binaires
- * array.c - décompilation des branchements conditionnels
+ * if.c - décompilation des branchements conditionnels
  *
- * Copyright (C) 2010-2012 Cyrille Bagard
+ * Copyright (C) 2010-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -35,7 +35,7 @@
 *  Paramètres  : instr = instruction d'origine à convertir.                   *
 *                ctx   = contexte de la phase de décompilation.               *
 *                                                                             *
-*  Description : Décompile une instruction de comparaison d'opérandes.        *
+*  Description : Décompile une instruction de branchement conditionnel.       *
 *                                                                             *
 *  Retour      : Instruction mise en place ou NULL.                           *
 *                                                                             *
@@ -104,7 +104,7 @@ GDecInstruction *dalvik_decomp_instr_if(const GArchInstruction *instr, GDecConte
 *  Paramètres  : instr = instruction d'origine à convertir.                   *
 *                ctx   = contexte de la phase de décompilation.               *
 *                                                                             *
-*  Description : Décompile une instruction de comparaison d'opérandes.        *
+*  Description : Décompile une instruction de branchement conditionnel.       *
 *                                                                             *
 *  Retour      : Instruction mise en place ou NULL.                           *
 *                                                                             *
diff --git a/src/arch/dalvik/decomp/switch.c b/src/arch/dalvik/decomp/switch.c
new file mode 100644
index 0000000..83da613
--- /dev/null
+++ b/src/arch/dalvik/decomp/switch.c
@@ -0,0 +1,62 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * switch.c - décompilation des aiguillages multiples du flot d'exécution
+ *
+ * Copyright (C) 2013 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "translate.h"
+
+
+
+#include "../instruction.h"
+#include "../../../decomp/instr/switch.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instruction d'origine à convertir.                   *
+*                ctx   = contexte de la phase de décompilation.               *
+*                                                                             *
+*  Description : Décompile une instruction d'aiguillages multiples du flux.   *
+*                                                                             *
+*  Retour      : Instruction mise en place ou NULL.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GDecInstruction *dalvik_decomp_instr_switch(const GArchInstruction *instr, GDecContext *ctx)
+{
+    GDecInstruction *result;                /* Instruction à retourner     */
+    vmpa_t addr;                            /* Adresse de l'instruction    */
+    GArchOperand *operand;                  /* Opérande de l'instruction   */
+    GDecInstruction *val;                   /* Valeur décidant du flot     */
+
+    g_arch_instruction_get_location(instr, NULL, NULL, &addr);
+
+    operand = g_arch_instruction_get_operand(instr, 0);
+    val = g_dec_context_convert_register(ctx, operand, false, addr);
+
+    result = g_switch_instruction_new(G_DEC_EXPRESSION(val));
+
+    return result;
+
+}
diff --git a/src/arch/dalvik/decomp/translate.h b/src/arch/dalvik/decomp/translate.h
index b8753db..1c9f19c 100644
--- a/src/arch/dalvik/decomp/translate.h
+++ b/src/arch/dalvik/decomp/translate.h
@@ -87,12 +87,15 @@ GDecInstruction *dalvik_decomp_instr_arithm_2addr(const GArchInstruction *, GDec
 /* Décompile une instruction de type 'opérations arithmétiques'. */
 GDecInstruction *dalvik_decomp_instr_arithm_lit(const GArchInstruction *, GDecContext *);
 
-/* Décompile une instruction de comparaison d'opérandes. */
+/* Décompile une instruction de branchement conditionnel. */
 GDecInstruction *dalvik_decomp_instr_if(const GArchInstruction *, GDecContext *);
 
-/* Décompile une instruction de comparaison d'opérandes. */
+/* Décompile une instruction de branchement conditionnel. */
 GDecInstruction *dalvik_decomp_instr_if_zero(const GArchInstruction *, GDecContext *);
 
+/* Décompile une instruction d'aiguillages multiples du flux. */
+GDecInstruction *dalvik_decomp_instr_switch(const GArchInstruction *, GDecContext *);
+
 
 
 #endif  /* _ANALYSIS_DECOMP_RTL_DALVIK_TRANSLATE_H */
diff --git a/src/arch/dalvik/instruction.c b/src/arch/dalvik/instruction.c
index 20982b7..81b8993 100644
--- a/src/arch/dalvik/instruction.c
+++ b/src/arch/dalvik/instruction.c
@@ -104,8 +104,8 @@ static dalvik_instruction _instructions[DOP_COUNT] = {
     [DOP_GOTO]                  = { 0x28, "goto" },
     [DOP_GOTO_16]               = { 0x29, "goto/16" },
     [DOP_GOTO_32]               = { 0x2a, "goto/32" },
-    [DOP_PACKED_SWITCH]         = { 0x2b, "packed-switch" },
-    [DOP_SPARSE_SWITCH]         = { 0x2c, "sparse-switch" },
+    [DOP_PACKED_SWITCH]         = { 0x2b, "packed-switch",      dalvik_decomp_instr_switch },
+    [DOP_SPARSE_SWITCH]         = { 0x2c, "sparse-switch",      dalvik_decomp_instr_switch },
     [DOP_CMPL_FLOAT]            = { 0x2d, "cmp-long" },
     [DOP_CMPG_FLOAT]            = { 0x2e, "cmpg-float" },
     [DOP_CMPL_DOUBLE]           = { 0x2f, "cmpl-double" },
diff --git a/src/arch/dalvik/opcodes/switch.c b/src/arch/dalvik/opcodes/switch.c
index 0feef9a..48576e9 100644
--- a/src/arch/dalvik/opcodes/switch.c
+++ b/src/arch/dalvik/opcodes/switch.c
@@ -1,6 +1,6 @@
 
 /* OpenIDA - Outil d'analyse de fichiers binaires
- * array.c - décodage de l'opération récupérant la longueur d'un tableau
+ * switch.c - décompilation des branchements multiples
  *
  * Copyright (C) 2012 Cyrille Bagard
  *
diff --git a/src/arch/instruction-int.h b/src/arch/instruction-int.h
index 25d65e5..d7da215 100644
--- a/src/arch/instruction-int.h
+++ b/src/arch/instruction-int.h
@@ -67,6 +67,7 @@ struct _GArchInstruction
     size_t from_count;                      /* Nombre de ces origines      */
     GArchInstruction **to;                  /* Eventuelles lignes visées   */
     InstructionLinkType *links_type;        /* Type des liens de dest.     */
+    link_extra_info *links_info;            /* Informations complémentaires*/
     size_t to_count;                        /* Nombre de ces destinations  */
 
     get_instruction_rw_regs_fc get_rw_regs; /* Liste des registres liés    */
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index 06d3e71..20b5f3a 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -2,7 +2,7 @@
 /* OpenIDA - Outil d'analyse de fichiers binaires
  * instruction.c - gestion générique des instructions
  *
- * Copyright (C) 2008-2012 Cyrille Bagard
+ * Copyright (C) 2008-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -24,6 +24,7 @@
 #include "instruction.h"
 
 
+#include <stdarg.h>
 #include <string.h>
 
 
@@ -350,6 +351,7 @@ bool g_arch_instruction_is_return(const GArchInstruction *instr)
 *  Paramètres  : instr = instruction dont les informations sont à consulter.  *
 *                dest  = ligne visée par la liaison (côté destination).       *
 *                type  = type de lien à construire.                           *
+*                ...   = éventuelles informations complémentaires.            *
 *                                                                             *
 *  Description : Etablit un lien entre deux instructions.                     *
 *                                                                             *
@@ -359,8 +361,10 @@ bool g_arch_instruction_is_return(const GArchInstruction *instr)
 *                                                                             *
 ******************************************************************************/
 
-void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type)
+void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *dest, InstructionLinkType type, ...)
 {
+    va_list ap;                             /* Gestion des variations      */
+
     /* Côté destination */
 
     dest->from = (GArchInstruction **)realloc(dest->from,
@@ -376,10 +380,24 @@ void g_arch_instruction_link_with(GArchInstruction *instr, GArchInstruction *des
                                              instr->to_count * sizeof(GArchInstruction *));
     instr->links_type = (InstructionLinkType *)realloc(instr->links_type,
                                                        instr->to_count * sizeof(InstructionLinkType));
+    instr->links_info = (link_extra_info *)realloc(instr->links_info,
+                                                   instr->to_count * sizeof(link_extra_info));
 
     instr->to[instr->to_count - 1] = dest;
     instr->links_type[instr->to_count - 1] = type;
 
+    va_start(ap, type);
+
+    switch (type)
+    {
+        case ILT_CASE_JUMP:
+            instr->links_info[instr->to_count - 1].imm = va_arg(ap, GImmOperand *);
+            break;
+        default:
+            break;
+    }
+
+    va_end(ap);
 
 }
 
@@ -429,6 +447,7 @@ bool g_arch_instruction_has_destinations(const GArchInstruction *instr)
 *  Paramètres  : instr = instruction dont les informations sont à consulter.  *
 *                dests = liste des instructions de destination. [OUT]         *
 *                types = liste des types de liens présents. [OUT]             *
+*                info  = éventuelles informations complémentaires. [OUT]      *
 *                                                                             *
 *  Description : Fournit les destinations d'une instruction donnée.           *
 *                                                                             *
@@ -438,10 +457,15 @@ bool g_arch_instruction_has_destinations(const GArchInstruction *instr)
 *                                                                             *
 ******************************************************************************/
 
-size_t g_arch_instruction_get_destinations(const GArchInstruction *instr, GArchInstruction ***dests, InstructionLinkType **types)
+size_t g_arch_instruction_get_destinations(const GArchInstruction *instr, GArchInstruction ***dests, InstructionLinkType **types, link_extra_info **info)
 {
     *dests = instr->to;
-    *types = instr->links_type;
+
+    if (types != NULL)
+        *types = instr->links_type;
+
+    if (info != NULL)
+        *info = instr->links_info;
 
     return instr->to_count;
 
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index 051ce51..ae53dbb 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -25,35 +25,18 @@
 #define _ARCH_INSTRUCTION_H
 
 
-#include <stdbool.h>
-#include <glib-object.h>
 #include <sys/types.h>
 
 
-#include "archbase.h"
-#include "operand.h"
+#include "immediate.h"
 #include "register.h"
+#include "../analysis/type.h"
 #include "../decomp/context.h"
 #include "../decomp/instruction.h"
 #include "../format/executable.h"
 
 
 
-/* Typage des instructions rencontrées */
-typedef enum _InstructionLinkType
-{
-    ILT_NONE,                               /* Aucune instruction visée    */
-    ILT_EXEC_FLOW,                          /* Raccord attendu entre blocs */
-    ILT_JUMP,                               /* Saut inconditionnel         */
-    ILT_CASE_JUMP,                          /* Saut suite à aiguillage     */
-    ILT_JUMP_IF_TRUE,                       /* Saut conditionnel (si vrai) */
-    ILT_JUMP_IF_FALSE,                      /* Saut conditionnel (si faux) */
-    ILT_CALL,                               /* Appel d'une fonction        */
-    ILT_CATCH_EXCEPTION                     /* Gestion d'une exception     */
-
-} InstructionLinkType;
-
-
 #define G_TYPE_ARCH_INSTRUCTION                 g_arch_instruction_get_type()
 #define G_ARCH_INSTRUCTION(obj)                 (G_TYPE_CHECK_INSTANCE_CAST((obj), g_arch_instruction_get_type(), GArchInstruction))
 #define G_IS_ARCH_INSTRUCTION(obj)              (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_arch_instruction_get_type()))
@@ -99,6 +82,29 @@ void g_arch_instruction_get_rw_registers(const GArchInstruction *, GArchRegister
 /* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
 
 
+/* Typage des instructions rencontrées */
+typedef enum _InstructionLinkType
+{
+    ILT_NONE,                               /* Aucune instruction visée    */
+    ILT_EXEC_FLOW,                          /* Raccord attendu entre blocs */
+    ILT_JUMP,                               /* Saut inconditionnel         */
+    ILT_CASE_JUMP,                          /* Saut suite à aiguillage     */
+    ILT_JUMP_IF_TRUE,                       /* Saut conditionnel (si vrai) */
+    ILT_JUMP_IF_FALSE,                      /* Saut conditionnel (si faux) */
+    ILT_CALL,                               /* Appel d'une fonction        */
+    ILT_CATCH_EXCEPTION                     /* Gestion d'une exception     */
+
+} InstructionLinkType;
+
+/* Informations complémentaires pour un lien */
+typedef union _link_extra_info
+{
+    GImmOperand *imm;                       /* Valeur d'un cas de switch() */
+    GDataType *type;                        /* Type d'une exception        */
+
+} link_extra_info;
+
+
 /* Informe sur une éventuelle référence à une autre instruction. */
 InstructionLinkType g_arch_instruction_get_link(const GArchInstruction *, vmpa_t *);
 
@@ -106,7 +112,7 @@ InstructionLinkType g_arch_instruction_get_link(const GArchInstruction *, vmpa_t
 bool g_arch_instruction_is_return(const GArchInstruction *instr);
 
 /* Etablit un lien entre deux instructions. */
-void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, InstructionLinkType);
+void g_arch_instruction_link_with(GArchInstruction *, GArchInstruction *, InstructionLinkType, ...);
 
 /* Indique si l'instruction a une ou plusieurs origines. */
 bool g_arch_instruction_has_sources(const GArchInstruction *);
@@ -115,7 +121,7 @@ bool g_arch_instruction_has_sources(const GArchInstruction *);
 bool g_arch_instruction_has_destinations(const GArchInstruction *);
 
 /* Fournit les destinations d'une instruction donnée. */
-size_t g_arch_instruction_get_destinations(const GArchInstruction *, GArchInstruction ***, InstructionLinkType **);
+size_t g_arch_instruction_get_destinations(const GArchInstruction *, GArchInstruction ***, InstructionLinkType **, link_extra_info **);
 
 /* Fournit la destination d'une instruction et d'un type donné. */
 GArchInstruction *g_arch_instruction_get_given_destination(const GArchInstruction *, InstructionLinkType);
diff --git a/src/decomp/expr/immediate.c b/src/decomp/expr/immediate.c
index 18af422..e0c6bd6 100644
--- a/src/decomp/expr/immediate.c
+++ b/src/decomp/expr/immediate.c
@@ -122,7 +122,7 @@ GDecInstruction *g_imm_expression_new(GImmOperand *operand)
     result = g_object_new(G_TYPE_IMM_EXPRESSION, NULL);
 
     result->operand = operand;
-    g_object_ref(G_OBJECT(operand));
+    g_object_ref(G_OBJECT(operand));    /* FIXME : ref pas déjà acquise ? */
 
     return G_DEC_INSTRUCTION(result);
 
diff --git a/src/decomp/instr/Makefile.am b/src/decomp/instr/Makefile.am
index b4e16eb..6120cac 100644
--- a/src/decomp/instr/Makefile.am
+++ b/src/decomp/instr/Makefile.am
@@ -2,7 +2,8 @@
 noinst_LTLIBRARIES = libdecompinstr.la
 
 libdecompinstr_la_SOURCES =				\
-	ite.h ite.c
+	ite.h ite.c							\
+	switch.h switch.c
 
 libdecompinstr_la_LDFLAGS = 
 
diff --git a/src/decomp/instr/ite.c b/src/decomp/instr/ite.c
index d78bb31..60627a6 100644
--- a/src/decomp/instr/ite.c
+++ b/src/decomp/instr/ite.c
@@ -1,8 +1,8 @@
 
 /* OpenIDA - Outil d'analyse de fichiers binaires
- * cond.c - représentation des conditions
+ * ite.c - représentation des branchements conditionnels
  *
- * Copyright (C) 2010 Cyrille Bagard
+ * Copyright (C) 2010-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -107,7 +107,7 @@ static void g_ite_instruction_class_init(GITEInstructionClass *klass)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : expr = instance à initialiser.                               *
+*  Paramètres  : instr = instance à initialiser.                              *
 *                                                                             *
 *  Description : Initialise une instance d'aiguillage du flux d'exécution.    *
 *                                                                             *
@@ -117,15 +117,15 @@ static void g_ite_instruction_class_init(GITEInstructionClass *klass)
 *                                                                             *
 ******************************************************************************/
 
-static void g_ite_instruction_init(GITEInstruction *expr)
+static void g_ite_instruction_init(GITEInstruction *instr)
 {
-    GDecInstruction *instr;                 /* Autre version de l'objet    */
+    GDecInstruction *base;                  /* Autre version de l'objet    */
 
-    instr = G_DEC_INSTRUCTION(expr);
+    base = G_DEC_INSTRUCTION(instr);
 
-    instr->visit = (dec_instr_visit_fc)g_ite_instruction_visit;
-    instr->replace = (dec_instr_replace_fc)g_ite_instruction_replace;
-    instr->print = (dec_instr_print_fc)g_ite_instruction_print;
+    base->visit = (dec_instr_visit_fc)g_ite_instruction_visit;
+    base->replace = (dec_instr_replace_fc)g_ite_instruction_replace;
+    base->print = (dec_instr_print_fc)g_ite_instruction_print;
 
 }
 
@@ -226,7 +226,7 @@ static bool g_ite_instruction_replace(GITEInstruction *instr, GDecInstruction *o
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : expr   = instruction à transcrire en version humaine.        *
+*  Paramètres  : instr  = instruction à transcrire en version humaine.        *
 *                buffer = tampon où doit se réaliser l'insertion.             *
 *                line   = ligne d'impression prête à emploi ou NULL.          *
 *                output = langage de programmation de sortie.                 *
@@ -239,24 +239,24 @@ static bool g_ite_instruction_replace(GITEInstruction *instr, GDecInstruction *o
 *                                                                             *
 ******************************************************************************/
 
-static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output)
+static GBufferLine *g_ite_instruction_print(const GITEInstruction *instr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output)
 {
     GBufferLine *result;                    /* Ligne à retourner           */
 
     g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "if ", 3, RTT_KEY_WORD);
 
-    if (expr->inverse)
+    if (instr->inverse)
         g_buffer_line_insert_text(line /* FIXME */, BLC_ASSEMBLY_HEAD, "!", 1, RTT_KEY_WORD);
 
-    result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->cond),
+    result = g_dec_instruction_print(G_DEC_INSTRUCTION(instr->cond),
                                      buffer, line, output);
 
-    result = g_dec_instruction_print(expr->true_branch, buffer, result, output);
+    result = g_dec_instruction_print(instr->true_branch, buffer, result, output);
 
-    if (expr->false_branch != NULL)
+    if (instr->false_branch != NULL)
     {
         g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "else", 4, RTT_KEY_WORD);
-        result = g_dec_instruction_print(expr->false_branch, buffer, result, output);
+        result = g_dec_instruction_print(instr->false_branch, buffer, result, output);
     }
 
     return result;
@@ -266,7 +266,7 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : cond         = expression fixant le choix de l'aiguillage.   *
+*  Paramètres  : instr        = expression fixant le choix de l'aiguillage.   *
 *                true_branch  = instructions si la condition est vérifiée.    *
 *                false_branch = instructions si la cond. n'est pas vérifiée.  *
 *                                                                             *
@@ -278,21 +278,21 @@ static GBufferLine *g_ite_instruction_print(const GITEInstruction *expr, GCodeBu
 *                                                                             *
 ******************************************************************************/
 
-void g_ite_instruction_set_branches(GITEInstruction *expr, GDecInstruction *true_branch, GDecInstruction *false_branch)
+void g_ite_instruction_set_branches(GITEInstruction *instr, GDecInstruction *true_branch, GDecInstruction *false_branch)
 {
 
     if (true_branch == NULL)
     {
-        expr->inverse = true;
+        instr->inverse = true;
 
-        expr->true_branch = false_branch;
-        expr->false_branch = true_branch;
+        instr->true_branch = false_branch;
+        instr->false_branch = true_branch;
 
     }
     else
     {
-        expr->true_branch = true_branch;
-        expr->false_branch = false_branch;
+        instr->true_branch = true_branch;
+        instr->false_branch = false_branch;
     }
 
 }
diff --git a/src/decomp/instr/ite.h b/src/decomp/instr/ite.h
index e53abe8..7137452 100644
--- a/src/decomp/instr/ite.h
+++ b/src/decomp/instr/ite.h
@@ -1,8 +1,8 @@
 
 /* OpenIDA - Outil d'analyse de fichiers binaires
- * ite.h - prototypes pour la représentation des conditions
+ * ite.h - prototypes pour la représentation des branchements conditionnels
  *
- * Copyright (C) 2010 Cyrille Bagard
+ * Copyright (C) 2010-2013 Cyrille Bagard
  *
  *  This file is part of OpenIDA.
  *
@@ -21,8 +21,8 @@
  */
 
 
-#ifndef _DECOMP_EXPR_ITE_H
-#define _DECOMP_EXPR_ITE_H
+#ifndef _DECOMP_INSTR_ITE_H
+#define _DECOMP_INSTR_ITE_H
 
 
 #include <glib-object.h>
@@ -52,12 +52,12 @@ typedef struct _GITEInstructionClass GITEInstructionClass;
 /* Indique le type défini pour un aiguillage du flux d'exécution. */
 GType g_ite_instruction_get_type(void);
 
-/* Détermine le corps des différentes branches possibles. */
-void g_ite_instruction_set_branches(GITEInstruction *, GDecInstruction *, GDecInstruction *);
-
 /* Exprime un aiguillage du flux en fonction d'une condition. */
 GDecInstruction *g_ite_instruction_new(GDecExpression *, vmpa_t, vmpa_t);
 
+/* Détermine le corps des différentes branches possibles. */
+void g_ite_instruction_set_branches(GITEInstruction *, GDecInstruction *, GDecInstruction *);
+
 
 
-#endif  /* _DECOMP_EXPR_ITE_H */
+#endif  /* _DECOMP_INSTR_ITE_H */
diff --git a/src/decomp/instr/switch.c b/src/decomp/instr/switch.c
new file mode 100644
index 0000000..3c204a0
--- /dev/null
+++ b/src/decomp/instr/switch.c
@@ -0,0 +1,379 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * switch.c - décodage des aiguillages multiples du flot d'exécution
+ *
+ * Copyright (C) 2013 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "switch.h"
+
+
+#include <malloc.h>
+#include <stdlib.h>
+
+
+#include "../instruction-int.h"
+
+
+/* Détails d'un cas */
+typedef struct _case_info
+{
+    vmpa_t addr;                            /* Adresse des blocs associés */
+
+    GDecExpression **values;                /* Valeur d'embranchement     */
+    size_t values_count;                    /* Quantité de cas rassemblés */
+
+    GDecInstruction *instrs;                /* Instructions du cas        */
+
+} case_info;
+
+
+/* Définition d'un aiguillage multiple du flux d'exécution (instance) */
+struct _GSwitchInstruction
+{
+    GDecInstruction parent;                 /* A laisser en premier        */
+
+    GDecExpression *value;                  /* Valeur décidant du flot     */
+
+    case_info *cases;                       /* Embranchements présents     */
+    size_t cases_count;                     /* Nombre de cas de sélection  */
+
+    GDecInstruction *def_case;              /* Instructions par défaut     */
+
+};
+
+
+/* Définition d'un aiguillage multiple du flux d'exécution (classe) */
+struct _GSwitchInstructionClass
+{
+    GDecInstructionClass parent;            /* A laisser en premier        */
+
+};
+
+
+
+/* Initialise la classe des aiguillages de flux d'exécution. */
+static void g_switch_instruction_class_init(GSwitchInstructionClass *);
+
+/* Initialise une instance d'aiguillage du flux d'exécution. */
+static void g_switch_instruction_init(GSwitchInstruction *);
+
+/* Visite un ensemble hiérarchique d'instructions décompilées. */
+static bool g_switch_instruction_visit(GSwitchInstruction *, dec_instr_visitor_cb, DecInstrVisitFlags, void *);
+
+/* Remplace une instruction décompilée par une autre. */
+static bool g_switch_instruction_replace(GSwitchInstruction *, GDecInstruction *, GDecInstruction *);
+
+/* Imprime pour l'écran un version humaine d'une instruction. */
+static GBufferLine *g_switch_instruction_print(const GSwitchInstruction *, GCodeBuffer *, GBufferLine *, GLangOutput *);
+
+
+
+/* Indique le type défini pour un aiguillage du flux d'exécution. */
+G_DEFINE_TYPE(GSwitchInstruction, g_switch_instruction, G_TYPE_DEC_INSTRUCTION);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des aiguillages de flux d'exécution.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_switch_instruction_class_init(GSwitchInstructionClass *klass)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instance à initialiser.                              *
+*                                                                             *
+*  Description : Initialise une instance d'aiguillage du flux d'exécution.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_switch_instruction_init(GSwitchInstruction *instr)
+{
+    GDecInstruction *base;                  /* Autre version de l'objet    */
+
+    base = G_DEC_INSTRUCTION(instr);
+
+    base->visit = (dec_instr_visit_fc)g_switch_instruction_visit;
+    base->replace = (dec_instr_replace_fc)g_switch_instruction_replace;
+    base->print = (dec_instr_print_fc)g_switch_instruction_print;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : value = valeur déterminant la voie à suivre.                 *
+*                                                                             *
+*  Description : Exprime un aiguillage multiple du flux selon une valeur.     *
+*                                                                             *
+*  Retour      : Expression mise en place.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GDecInstruction *g_switch_instruction_new(GDecExpression *value)
+{
+    GSwitchInstruction *result;              /* Expression à retourner      */
+
+    result = g_object_new(G_TYPE_SWITCH_INSTRUCTION, NULL);
+
+    result->value = value;
+
+    return G_DEC_INSTRUCTION(result);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr    = première instruction à venir visiter.             *
+*                callback = procédure à appeler à chaque instruction visitée. *
+*                flags    = moments des appels à réaliser en retour.          *
+*                data     = données quelconques associées au visiteur.        *
+*                                                                             *
+*  Description : Visite un ensemble hiérarchique d'instructions décompilées.  *
+*                                                                             *
+*  Retour      : true si le parcours a été jusqu'à son terme, false sinon.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_switch_instruction_visit(GSwitchInstruction *instr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+    return true;
+    for (i = 0; i < instr->cases_count && result; i++)
+        result = _g_dec_instruction_visit(instr->cases[i].instrs, G_DEC_INSTRUCTION(instr),
+                                          callback, flags, data);
+
+    if (result && instr->def_case != NULL)
+        result = _g_dec_instruction_visit(instr->def_case, G_DEC_INSTRUCTION(instr),
+                                          callback, flags, data);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = première instruction à venir ausculter.              *
+*                old   = instruction décompilée à venir remplacer.            *
+*                new   = instruction décompilée à utiliser dorénavant.        *
+*                                                                             *
+*  Description : Remplace une instruction décompilée par une autre.           *
+*                                                                             *
+*  Retour      : true si un remplacement a été effectué, false sinon.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_switch_instruction_replace(GSwitchInstruction *instr, GDecInstruction *old, GDecInstruction *new)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = false;
+    return false;
+    for (i = 0; i < instr->cases_count; i++)
+        result |= g_dec_instruction_replace(instr->cases[i].instrs, old, new);
+
+    if (instr->def_case != NULL)
+        result |= g_dec_instruction_replace(instr->def_case, old, new);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr  = instruction à transcrire en version humaine.        *
+*                buffer = tampon où doit se réaliser l'insertion.             *
+*                line   = ligne d'impression prête à emploi ou NULL.          *
+*                output = langage de programmation de sortie.                 *
+*                                                                             *
+*  Description : Imprime pour l'écran un version humaine d'une instruction.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GBufferLine *g_switch_instruction_print(const GSwitchInstruction *instr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output)
+{
+    GBufferLine *result;                    /* Ligne à retourner           */
+    size_t i;                               /* Boucle de parcours #1       */
+    size_t j;                               /* Boucle de parcours #2       */
+
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "switch", 9, RTT_KEY_WORD);
+
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, " ", 1, RTT_RAW);
+    g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "(", 1, RTT_PUNCT);
+
+    result = g_dec_instruction_print(G_DEC_INSTRUCTION(instr->value), buffer, line, output);
+
+    g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, ")", 1, RTT_PUNCT);
+
+    g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 1, RTT_RAW);
+    g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "{", 1, RTT_HOOK);
+
+    g_code_buffer_inc_indentation(buffer);
+
+    /* Cas d'aiguillage définis */
+
+    for (i = 0; i < instr->cases_count; i++)
+    {
+        for (j = 0; j < instr->cases[i].values_count; j++)
+        {
+            result = g_code_buffer_append_new_line_fixme(buffer);
+
+            g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "case", 4, RTT_KEY_WORD);
+            g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 1, RTT_RAW);
+
+            result = g_dec_instruction_print(G_DEC_INSTRUCTION(instr->cases[i].values[j])
+                                             , buffer, result, output);
+
+            g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT);
+
+        }
+
+        result = g_dec_instruction_print(instr->cases[i].instrs, buffer, result, output);
+
+    }
+
+    /* Cas par défaut */
+
+    if (instr->def_case != NULL)
+    {
+        result = g_code_buffer_append_new_line_fixme(buffer);
+
+        g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "default", 7, RTT_KEY_WORD);
+        g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT);
+
+        result = g_dec_instruction_print(instr->def_case, buffer, result, output);
+
+    }
+
+    /* Clôture */
+
+    g_code_buffer_dec_indentation(buffer);
+
+    result = g_code_buffer_append_new_line_fixme(buffer);
+
+    g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, "}", 1, RTT_HOOK);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr  = instruction à compléter avec un nouveau cas.        *
+*                value  = valeur validant l'exécution des instructions.       *
+*                instrs = instructions associées au cas présenté.             *
+*                addr   = adresse du bloc d'instructions.                     *
+*                                                                             *
+*  Description : Ajoute un cas d'exécution à l'aiguillage multiple.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_switch_instruction_add_case(GSwitchInstruction *instr, GDecExpression *value, GDecInstruction *instrs, vmpa_t addr)
+{
+    case_info *found;                       /* Cas similaires déjà intégrés*/
+
+    found = (case_info *)bsearch(&addr, instr->cases, instr->cases_count, sizeof(case_info),
+                                 (__compar_fn_t)compare_vmpa);
+
+    if (found != NULL)
+    {
+        found->values = (GDecExpression **)realloc(found->values,
+                                                   found->values_count++ * sizeof(GDecExpression *));
+
+        found->values[found->values_count - 1] = value;
+
+    }
+    else
+    {
+        instr->cases = (case_info *)realloc(instr->cases,
+                                            ++instr->cases_count * sizeof(case_info));
+
+        instr->cases[instr->cases_count - 1].addr = addr;
+        instr->cases[instr->cases_count - 1].values = (GDecExpression **)malloc(sizeof(GDecExpression *));
+        instr->cases[instr->cases_count - 1].values_count = 1;
+        instr->cases[instr->cases_count - 1].instrs = instrs;
+
+        instr->cases[instr->cases_count - 1].values[0] = value;
+
+        qsort(instr->cases, instr->cases_count, sizeof(case_info), (__compar_fn_t)compare_vmpa);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr  = instruction à compléter avec un nouveau cas.        *
+*                instrs = instructions associées au cas présenté.             *
+*                                                                             *
+*  Description : Ajoute un cas d'exécution par défaut à l'aiguillage multiple.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_switch_instruction_set_default_case(GSwitchInstruction *instr, GDecInstruction *instrs)
+{
+    if (instr->def_case != NULL)
+        g_object_unref(G_OBJECT(instr->def_case));
+
+    instr->def_case = instrs;
+
+}
diff --git a/src/decomp/instr/switch.h b/src/decomp/instr/switch.h
new file mode 100644
index 0000000..fa00c3e
--- /dev/null
+++ b/src/decomp/instr/switch.h
@@ -0,0 +1,66 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * switch.h - prototypes pour les aiguillages multiples du flot d'exécution
+ *
+ * Copyright (C) 2013 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _DECOMP_INSTR_SWITCH_H
+#define _DECOMP_INSTR_SWITCH_H
+
+
+#include <glib-object.h>
+
+
+#include "../expression.h"
+#include "../instruction.h"
+
+
+
+#define G_TYPE_SWITCH_INSTRUCTION               g_switch_instruction_get_type()
+#define G_SWITCH_INSTRUCTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_switch_instruction_get_type(), GSwitchInstruction))
+#define G_IS_SWITCH_INSTRUCTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_switch_instruction_get_type()))
+#define G_SWITCH_INSTRUCTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SWITCH_INSTRUCTION, GSwitchInstructionClass))
+#define G_IS_SWITCH_INSTRUCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SWITCH_INSTRUCTION))
+#define G_SWITCH_INSTRUCTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SWITCH_INSTRUCTION, GSwitchInstructionClass))
+
+
+
+/* Définition d'un aiguillage multiple du flux d'exécution (instance) */
+typedef struct _GSwitchInstruction GSwitchInstruction;
+
+/* Définition d'un aiguillage multiple du flux d'exécution (classe) */
+typedef struct _GSwitchInstructionClass GSwitchInstructionClass;
+
+
+/* Indique le type défini pour un multiple aiguillage du flux d'exécution. */
+GType g_switch_instruction_get_type(void);
+
+/* Exprime un aiguillage multiple du flux selon une valeur. */
+GDecInstruction *g_switch_instruction_new(GDecExpression *);
+
+/* Ajoute un cas d'exécution à l'aiguillage multiple. */
+void g_switch_instruction_add_case(GSwitchInstruction *, GDecExpression *, GDecInstruction *, vmpa_t);
+
+/* Ajoute un cas d'exécution par défaut à l'aiguillage multiple. */
+void g_switch_instruction_set_default_case(GSwitchInstruction *, GDecInstruction *);
+
+
+
+#endif  /* _DECOMP_INSTR_SWITCH_H */
diff --git a/src/gtkext/graph/layout.c b/src/gtkext/graph/layout.c
index 2cf4a36..87ae2ec 100644
--- a/src/gtkext/graph/layout.c
+++ b/src/gtkext/graph/layout.c
@@ -244,7 +244,7 @@ static char *complete_graph_links(const GtkGraphView *view, GtkViewPanel **views
 
         if (g_arch_instruction_has_destinations(last))
         {
-            dcount = g_arch_instruction_get_destinations(last, &dests, &types);
+            dcount = g_arch_instruction_get_destinations(last, &dests, &types, NULL);
 
             for (j = 0; j < dcount; j++)
             {
-- 
cgit v0.11.2-87-g4458