From f94210f2617968774277078a8db9097c56029039 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 22 Aug 2020 19:57:19 +0200
Subject: Defined paths to access to the instruction operands.

---
 plugins/arm/v7/operands/maccess.c       | 154 ++++++++++++++++-
 plugins/arm/v7/operands/offset.c        |  83 ++++++++-
 plugins/arm/v7/operands/rotation.c      | 106 +++++++++++-
 plugins/arm/v7/operands/shift.c         |  83 ++++++++-
 plugins/dalvik/operands/args.c          | 137 ++++++++++++++-
 plugins/pychrysalide/arch/instruction.c | 126 ++++++++++++++
 plugins/pychrysalide/arch/operand.c     | 298 +++++++++++++++++++++++++++++++-
 src/arch/instruction.c                  | 143 +++++++++++++++
 src/arch/instruction.h                  |   7 +
 src/arch/operand-int.h                  |   9 +
 src/arch/operand.c                      |  62 +++++++
 src/arch/operand.h                      |   6 +
 12 files changed, 1200 insertions(+), 14 deletions(-)

diff --git a/plugins/arm/v7/operands/maccess.c b/plugins/arm/v7/operands/maccess.c
index be3f0c9..aa0e9cf 100644
--- a/plugins/arm/v7/operands/maccess.c
+++ b/plugins/arm/v7/operands/maccess.c
@@ -24,8 +24,15 @@
 #include "maccess.h"
 
 
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
 #include <arch/operand-int.h>
+#include <common/cpp.h>
 #include <common/sort.h>
+#include <core/logs.h>
 #include <gtkext/gtkblockdisplay.h>
 
 
@@ -67,6 +74,12 @@ static void g_armv7_maccess_operand_finalize(GArmV7MAccessOperand *);
 /* Compare un opérande avec un autre. */
 static int g_armv7_maccess_operand_compare(const GArmV7MAccessOperand *, const GArmV7MAccessOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static char *g_armv7_maccess_operand_find_inner_operand_path(const GArmV7MAccessOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static GArchOperand *g_armv7_maccess_operand_get_inner_operand_from_path(const GArmV7MAccessOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 static void g_armv7_maccess_operand_print(const GArmV7MAccessOperand *, GBufferLine *);
 
@@ -105,12 +118,16 @@ static void g_armv7_maccess_operand_class_init(GArmV7MAccessOperandClass *klass)
     GArchOperandClass *operand;             /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
-    operand = G_ARCH_OPERAND_CLASS(klass);
 
     object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_maccess_operand_dispose;
     object->finalize = (GObjectFinalizeFunc)g_armv7_maccess_operand_finalize;
 
+    operand = G_ARCH_OPERAND_CLASS(klass);
+
     operand->compare = (operand_compare_fc)g_armv7_maccess_operand_compare;
+    operand->find_inner = (find_inner_operand_fc)g_armv7_maccess_operand_find_inner_operand_path;
+    operand->get_inner = (get_inner_operand_fc)g_armv7_maccess_operand_get_inner_operand_from_path;
+
     operand->print = (operand_print_fc)g_armv7_maccess_operand_print;
 
     operand->unserialize = (unserialize_operand_fc)g_armv7_maccess_operand_unserialize;
@@ -227,6 +244,141 @@ static int g_armv7_maccess_operand_compare(const GArmV7MAccessOperand *a, const
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_armv7_maccess_operand_find_inner_operand_path(const GArmV7MAccessOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+    size_t count;                           /* Nombre d'opérandes en place */
+    size_t i;                               /* Boucle de parcours          */
+    int ret;                                /* Bilan d'une construction    */
+    char *sub_path;                         /* Sous-chemin emprunté        */
+
+    GArchOperand *candidates[] = { operand->base, operand->offset, operand->shift };
+
+    result = NULL;
+
+    count = ARRAY_SIZE(candidates);
+
+    /* Première passe : accès direct */
+
+    for (i = 0; i < count && result == NULL; i++)
+    {
+        if (candidates[i] == NULL)
+            continue;
+
+        if (candidates[i] == target)
+        {
+            ret = asprintf(&result, "%zu", i);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+        }
+
+    }
+
+    /* Seconde passe : accès profond */
+
+    for (i = 0; i < count && result == NULL; i++)
+    {
+        if (candidates[i] == NULL)
+            continue;
+
+        sub_path = g_arch_operand_find_inner_operand_path(candidates[i], target);
+
+        if (sub_path != NULL)
+        {
+            ret = asprintf(&result, "%zu:%s", i, sub_path);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+
+            free(sub_path);
+
+        }
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand *g_armv7_maccess_operand_get_inner_operand_from_path(const GArmV7MAccessOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+    size_t index;                           /* Indice de l'opérande visé   */
+    char *end;                              /* Poursuite du parcours ?     */
+    GArchOperand *found;                    /* Opérande trouvé             */
+
+    GArchOperand *candidates[] = { operand->base, operand->offset, operand->shift };
+
+    result = NULL;
+
+    /* Recherche au premier niveau */
+
+    index = strtoul(path, &end, 10);
+
+    if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL))
+    {
+        LOG_ERROR_N("strtoul");
+        goto done;
+    }
+
+    if (index >= ARRAY_SIZE(candidates))
+        goto done;
+
+    found = candidates[index];
+    if (found == NULL) goto done;
+
+    if (*end == '\0')
+    {
+        result = found;
+        g_object_ref(G_OBJECT(result));
+        goto done;
+    }
+
+    /* Recherche en profondeur */
+
+    assert(*end == ':');
+
+    result = g_arch_operand_get_inner_operand_from_path(found, end + 1);
+
+ done:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande à traiter.                                *
 *                line    = ligne tampon où imprimer l'opérande donné.         *
 *                                                                             *
diff --git a/plugins/arm/v7/operands/offset.c b/plugins/arm/v7/operands/offset.c
index 6bcacaf..967b296 100644
--- a/plugins/arm/v7/operands/offset.c
+++ b/plugins/arm/v7/operands/offset.c
@@ -24,6 +24,10 @@
 #include "offset.h"
 
 
+#include <stdio.h>
+#include <string.h>
+
+
 #include <arch/operand-int.h>
 #include <common/sort.h>
 #include <gtkext/gtkblockdisplay.h>
@@ -64,6 +68,12 @@ static void g_armv7_offset_operand_finalize(GArmV7OffsetOperand *);
 /* Compare un opérande avec un autre. */
 static int g_armv7_offset_operand_compare(const GArmV7OffsetOperand *, const GArmV7OffsetOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static char *g_armv7_offset_operand_find_inner_operand_path(const GArmV7OffsetOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static GArchOperand *g_armv7_offset_operand_get_inner_operand_from_path(const GArmV7OffsetOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 static void g_armv7_offset_operand_print(const GArmV7OffsetOperand *, GBufferLine *);
 
@@ -102,12 +112,16 @@ static void g_armv7_offset_operand_class_init(GArmV7OffsetOperandClass *klass)
     GArchOperandClass *operand;             /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
-    operand = G_ARCH_OPERAND_CLASS(klass);
 
     object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_offset_operand_dispose;
     object->finalize = (GObjectFinalizeFunc)g_armv7_offset_operand_finalize;
 
+    operand = G_ARCH_OPERAND_CLASS(klass);
+
     operand->compare = (operand_compare_fc)g_armv7_offset_operand_compare;
+    operand->find_inner = (find_inner_operand_fc)g_armv7_offset_operand_find_inner_operand_path;
+    operand->get_inner = (get_inner_operand_fc)g_armv7_offset_operand_get_inner_operand_from_path;
+
     operand->print = (operand_print_fc)g_armv7_offset_operand_print;
 
     operand->unserialize = (unserialize_operand_fc)g_armv7_offset_operand_unserialize;
@@ -207,6 +221,73 @@ static int g_armv7_offset_operand_compare(const GArmV7OffsetOperand *a, const GA
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_armv7_offset_operand_find_inner_operand_path(const GArmV7OffsetOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+
+    if (target == operand->value)
+        result = strdup("0");
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand *g_armv7_offset_operand_get_inner_operand_from_path(const GArmV7OffsetOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+
+    if (strncmp(path, "0", 1) == 0)
+        switch (path[1])
+        {
+            case '\0':
+                result = operand->value;
+                g_object_ref(G_OBJECT(result));
+                break;
+
+            case ':':
+                result = g_arch_operand_get_inner_operand_from_path(operand->value, path + 1);
+                break;
+
+            default:
+                result = NULL;
+                break;
+
+        }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande à traiter.                                *
 *                line    = ligne tampon où imprimer l'opérande donné.         *
 *                                                                             *
diff --git a/plugins/arm/v7/operands/rotation.c b/plugins/arm/v7/operands/rotation.c
index b6fe1cf..5db1d27 100644
--- a/plugins/arm/v7/operands/rotation.c
+++ b/plugins/arm/v7/operands/rotation.c
@@ -24,7 +24,12 @@
 #include "rotation.h"
 
 
+#include <stdio.h>
+#include <string.h>
+
+
 #include <arch/operand-int.h>
+#include <core/logs.h>
 #include <gtkext/gtkblockdisplay.h>
 
 
@@ -62,6 +67,12 @@ static void g_armv7_rotation_operand_finalize(GArmV7RotationOperand *);
 /* Compare un opérande avec un autre. */
 static int g_armv7_rotation_operand_compare(const GArmV7RotationOperand *, const GArmV7RotationOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static char *g_armv7_rotation_operand_find_inner_operand_path(const GArmV7RotationOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static GArchOperand *g_armv7_rotation_operand_get_inner_operand_from_path(const GArmV7RotationOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 static void g_armv7_rotation_operand_print(const GArmV7RotationOperand *, GBufferLine *);
 
@@ -100,12 +111,16 @@ static void g_armv7_rotation_operand_class_init(GArmV7RotationOperandClass *klas
     GArchOperandClass *operand;             /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
-    operand = G_ARCH_OPERAND_CLASS(klass);
 
     object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_rotation_operand_dispose;
     object->finalize = (GObjectFinalizeFunc)g_armv7_rotation_operand_finalize;
 
+    operand = G_ARCH_OPERAND_CLASS(klass);
+
     operand->compare = (operand_compare_fc)g_armv7_rotation_operand_compare;
+    operand->find_inner = (find_inner_operand_fc)g_armv7_rotation_operand_find_inner_operand_path;
+    operand->get_inner = (get_inner_operand_fc)g_armv7_rotation_operand_get_inner_operand_from_path;
+
     operand->print = (operand_print_fc)g_armv7_rotation_operand_print;
 
     operand->unserialize = (unserialize_operand_fc)g_armv7_rotation_operand_unserialize;
@@ -200,6 +215,95 @@ static int g_armv7_rotation_operand_compare(const GArmV7RotationOperand *a, cons
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_armv7_rotation_operand_find_inner_operand_path(const GArmV7RotationOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+    char *sub_path;                         /* Sous-chemin emprunté        */
+    int ret;                                /* Bilan d'une construction    */
+
+    if (target == operand->value)
+        result = strdup("0");
+
+    else
+    {
+        sub_path = g_arch_operand_find_inner_operand_path(operand->value, target);
+
+        if (sub_path != NULL)
+        {
+            ret = asprintf(&result, "0:%s", sub_path);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+
+            free(sub_path);
+
+        }
+
+        else
+            result = NULL;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand *g_armv7_rotation_operand_get_inner_operand_from_path(const GArmV7RotationOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+
+    if (strncmp(path, "0", 1) == 0)
+        switch (path[1])
+        {
+            case '\0':
+                result = operand->value;
+                g_object_ref(G_OBJECT(result));
+                break;
+
+            case ':':
+                result = g_arch_operand_get_inner_operand_from_path(operand->value, path + 1);
+                break;
+
+            default:
+                result = NULL;
+                break;
+
+        }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande à traiter.                                *
 *                line    = ligne tampon où imprimer l'opérande donné.         *
 *                                                                             *
diff --git a/plugins/arm/v7/operands/shift.c b/plugins/arm/v7/operands/shift.c
index a0c345a..8da666e 100644
--- a/plugins/arm/v7/operands/shift.c
+++ b/plugins/arm/v7/operands/shift.c
@@ -24,6 +24,10 @@
 #include "shift.h"
 
 
+#include <stdio.h>
+#include <string.h>
+
+
 #include <arch/operand-int.h>
 #include <common/sort.h>
 #include <gtkext/gtkblockdisplay.h>
@@ -64,6 +68,12 @@ static void g_armv7_shift_operand_finalize(GArmV7ShiftOperand *);
 /* Compare un opérande avec un autre. */
 static int g_armv7_shift_operand_compare(const GArmV7ShiftOperand *, const GArmV7ShiftOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static char *g_armv7_shift_operand_find_inner_operand_path(const GArmV7ShiftOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static GArchOperand *g_armv7_shift_operand_get_inner_operand_from_path(const GArmV7ShiftOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 static void g_armv7_shift_operand_print(const GArmV7ShiftOperand *, GBufferLine *);
 
@@ -102,12 +112,16 @@ static void g_armv7_shift_operand_class_init(GArmV7ShiftOperandClass *klass)
     GArchOperandClass *operand;             /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
-    operand = G_ARCH_OPERAND_CLASS(klass);
 
     object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_shift_operand_dispose;
     object->finalize = (GObjectFinalizeFunc)g_armv7_shift_operand_finalize;
 
+    operand = G_ARCH_OPERAND_CLASS(klass);
+
     operand->compare = (operand_compare_fc)g_armv7_shift_operand_compare;
+    operand->find_inner = (find_inner_operand_fc)g_armv7_shift_operand_find_inner_operand_path;
+    operand->get_inner = (get_inner_operand_fc)g_armv7_shift_operand_get_inner_operand_from_path;
+
     operand->print = (operand_print_fc)g_armv7_shift_operand_print;
 
     operand->unserialize = (unserialize_operand_fc)g_armv7_shift_operand_unserialize;
@@ -207,6 +221,73 @@ static int g_armv7_shift_operand_compare(const GArmV7ShiftOperand *a, const GArm
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_armv7_shift_operand_find_inner_operand_path(const GArmV7ShiftOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+
+    if (target == operand->shift_value)
+        result = strdup("0");
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand *g_armv7_shift_operand_get_inner_operand_from_path(const GArmV7ShiftOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+
+    if (strncmp(path, "0", 1) == 0)
+        switch (path[1])
+        {
+            case '\0':
+                result = operand->shift_value;
+                g_object_ref(G_OBJECT(result));
+                break;
+
+            case ':':
+                result = g_arch_operand_get_inner_operand_from_path(operand->shift_value, path + 1);
+                break;
+
+            default:
+                result = NULL;
+                break;
+
+        }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande à traiter.                                *
 *                line    = ligne tampon où imprimer l'opérande donné.         *
 *                                                                             *
diff --git a/plugins/dalvik/operands/args.c b/plugins/dalvik/operands/args.c
index a536e8c..4b87e5e 100644
--- a/plugins/dalvik/operands/args.c
+++ b/plugins/dalvik/operands/args.c
@@ -26,10 +26,13 @@
 
 #include <assert.h>
 #include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 
 #include <arch/operand-int.h>
 #include <common/sort.h>
+#include <core/logs.h>
 #include <gtkext/gtkblockdisplay.h>
 
 
@@ -68,6 +71,12 @@ static void g_dalvik_args_operand_finalize(GDalvikArgsOperand *);
 /* Compare un opérande avec un autre. */
 static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *, const GDalvikArgsOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static char *g_dalvik_args_operand_find_inner_operand_path(const GDalvikArgsOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static GArchOperand *g_dalvik_args_operand_get_inner_operand_from_path(const GDalvikArgsOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 static void g_dalvik_args_operand_print(const GDalvikArgsOperand *, GBufferLine *);
 
@@ -106,12 +115,16 @@ static void g_dalvik_args_operand_class_init(GDalvikArgsOperandClass *klass)
     GArchOperandClass *operand;             /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
-    operand = G_ARCH_OPERAND_CLASS(klass);
 
     object->dispose = (GObjectFinalizeFunc/* ! */)g_dalvik_args_operand_dispose;
     object->finalize = (GObjectFinalizeFunc)g_dalvik_args_operand_finalize;
 
+    operand = G_ARCH_OPERAND_CLASS(klass);
+
     operand->compare = (operand_compare_fc)g_dalvik_args_operand_compare;
+    operand->find_inner = (find_inner_operand_fc)g_dalvik_args_operand_find_inner_operand_path;
+    operand->get_inner = (get_inner_operand_fc)g_dalvik_args_operand_get_inner_operand_from_path;
+
     operand->print = (operand_print_fc)g_dalvik_args_operand_print;
 
     operand->unserialize = (unserialize_operand_fc)g_dalvik_args_operand_unserialize;
@@ -224,6 +237,128 @@ static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *a, const GDal
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_dalvik_args_operand_find_inner_operand_path(const GDalvikArgsOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+    size_t i;                               /* Boucle de parcours          */
+    int ret;                                /* Bilan d'une construction    */
+    char *sub_path;                         /* Sous-chemin emprunté        */
+
+    result = NULL;
+
+    /* Première passe : accès direct */
+
+    for (i = 0; i < operand->count && result == NULL; i++)
+    {
+        if (operand->args[i] == target)
+        {
+            ret = asprintf(&result, "%zu", i);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+        }
+
+    }
+
+    /* Seconde passe : accès profond */
+
+    for (i = 0; i < operand->count && result == NULL; i++)
+    {
+        sub_path = g_arch_operand_find_inner_operand_path(operand->args[i], target);
+
+        if (sub_path != NULL)
+        {
+            ret = asprintf(&result, "%zu:%s", i, sub_path);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+
+            free(sub_path);
+
+        }
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand *g_dalvik_args_operand_get_inner_operand_from_path(const GDalvikArgsOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+    size_t index;                           /* Indice de l'opérande visé   */
+    char *end;                              /* Poursuite du parcours ?     */
+    GArchOperand *found;                    /* Opérande trouvé             */
+
+    result = NULL;
+
+    /* Recherche au premier niveau */
+
+    index = strtoul(path, &end, 10);
+
+    if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL))
+    {
+        LOG_ERROR_N("strtoul");
+        goto done;
+    }
+
+    if (index >= operand->count)
+        goto done;
+
+    found = operand->args[index];
+    if (found == NULL) goto done;
+
+    if (*end == '\0')
+    {
+        result = found;
+        g_object_ref(G_OBJECT(result));
+        goto done;
+    }
+
+    /* Recherche en profondeur */
+
+    assert(*end == ':');
+
+    result = g_arch_operand_get_inner_operand_from_path(found, end + 1);
+
+ done:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande à traiter.                                *
 *                line    = ligne tampon où imprimer l'opérande donné.         *
 *                                                                             *
diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c
index 058106d..fcd0c83 100644
--- a/plugins/pychrysalide/arch/instruction.c
+++ b/plugins/pychrysalide/arch/instruction.c
@@ -26,6 +26,7 @@
 
 
 #include <assert.h>
+#include <malloc.h>
 #include <string.h>
 #include <pygobject.h>
 
@@ -122,6 +123,12 @@ static PyObject *py_arch_instruction_replace_operand(PyObject *, PyObject *);
 /* Détache un opérande liée d'une instruction. */
 static PyObject *py_arch_instruction_detach_operand(PyObject *, PyObject *);
 
+/* Détermine le chemin conduisant à un opérande. */
+static PyObject *py_arch_instruction_find_operand_path(PyObject *, PyObject *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static PyObject *py_arch_instruction_get_operand_from_path(PyObject *, PyObject *);
+
 
 
 /* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
@@ -578,6 +585,123 @@ static PyObject *py_arch_instruction_detach_operand(PyObject *self, PyObject *ar
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = architecture concernée par la procédure.              *
+*                args = instruction représentant le point de départ.          *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande.                *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou None en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_instruction_find_operand_path(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Chemin à retourner          */
+    GArchOperand *target;                   /* Opérande ciblé par l'action */
+    int ret;                                /* Bilan de lecture des args.  */
+    GArchInstruction *instr;                /* Instruction manipulée       */
+    char *path;                             /* Chemin déterminé            */
+
+#define ARCH_INSTRUCTION_FIND_OPERAND_PATH_METHOD PYTHON_METHOD_DEF         \
+(                                                                           \
+    find_operand_path, "$self, target, /",                                  \
+    METH_VARARGS, py_arch_instruction,                                      \
+    "Compute the path leading to an instruction operand.\n"                 \
+    "\n"                                                                    \
+    "The *target* has to be an instance of pychrysalide.arch.ArchOperand"   \
+    " included in the instruction.\n"                                       \
+    "\n"                                                                    \
+    "The result is a string of the form 'n[:n:n:n]', where n is an"         \
+    " internal index, or None if the *target* is not found. This kind of"   \
+    " path is aimed to be built for the"                                    \
+    " pychrysalide.arch.ArchInstruction.find_operand_path() function."      \
+)
+
+    ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &target);
+    if (!ret) return NULL;
+
+    instr = G_ARCH_INSTRUCTION(pygobject_get(self));
+
+    path = g_arch_instruction_find_operand_path(instr, target);
+
+    if (path != NULL)
+    {
+        result = PyUnicode_FromString(path);
+        free(path);
+    }
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = architecture concernée par la procédure.              *
+*                args = instruction représentant le point de départ.          *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou None en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_instruction_get_operand_from_path(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Trouvaille à retourner      */
+    const char *path;                       /* Chemin à parcourir          */
+    int ret;                                /* Bilan de lecture des args.  */
+    GArchInstruction *instr;                /* Instruction manipulée       */
+    GArchOperand *op;                       /* Opérande retrouvé           */
+
+#define ARCH_INSTRUCTION_GET_OPERAND_FROM_PATH_METHOD PYTHON_METHOD_DEF     \
+(                                                                           \
+    get_operand_from_path, "$self, path, /",                                \
+    METH_VARARGS, py_arch_instruction,                                      \
+    "Retrieve an operand from an instruction by its path.\n"                \
+    "\n"                                                                    \
+    "This *path* is a string of the form 'n[:n:n:n]', where n is an"        \
+    " internal index. Such a path is usually built by the"                  \
+    " pychrysalide.arch.ArchInstruction.find_operand_path() function.\n"    \
+    "\n"                                                                    \
+    "The result is an pychrysalide.arch.ArchOperand instance, or"           \
+    " None if no operand was found."                                        \
+)
+
+    ret = PyArg_ParseTuple(args, "s", &path);
+    if (!ret) return NULL;
+
+    instr = G_ARCH_INSTRUCTION(pygobject_get(self));
+
+    op = g_arch_instruction_get_operand_from_path(instr, path);
+
+    if (op != NULL)
+    {
+        result = pygobject_new(G_OBJECT(op));
+        g_object_unref(G_OBJECT(op));
+    }
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                     DEFINITION DES LIAISONS ENTRE INSTRUCTIONS                     */
@@ -859,6 +983,8 @@ PyTypeObject *get_python_arch_instruction_type(void)
             METH_VARARGS,
             "detach_operand($self, target, /)\n--\n\nRemove an operand from the instruction."
         },
+        ARCH_INSTRUCTION_FIND_OPERAND_PATH_METHOD,
+        ARCH_INSTRUCTION_GET_OPERAND_FROM_PATH_METHOD,
         { NULL }
     };
 
diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c
index 019e4a2..7fa5118 100644
--- a/plugins/pychrysalide/arch/operand.c
+++ b/plugins/pychrysalide/arch/operand.c
@@ -50,6 +50,12 @@ static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer);
 /* Compare un opérande avec un autre. */
 static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const GArchOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 static void py_arch_operand_print_wrapper(const GArchOperand *, GBufferLine *);
 
@@ -64,6 +70,12 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const G
 /* Effectue une comparaison avec un objet Python 'ArchOperand'. */
 static PyObject *py_arch_operand_richcompare(PyObject *, PyObject *, int);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+static PyObject *py_arch_operand_find_inner_operand_path(PyObject *, PyObject *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *, PyObject *);
+
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -105,6 +117,10 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec
     "* pychrysalide.arch.ArchRegister._print();\n"                      \
     "* pychrysalide.arch.ArchRegister._build_tooltip().\n"              \
     "\n"                                                                \
+    "Some extra method definitions are optional for new classes:\n"     \
+    "* pychrysalide.arch.ArchRegister._find_inner_operand_path();\n"    \
+    "* pychrysalide.arch.ArchRegister._get_inner_operand_from_path().\n"\
+    "\n"                                                                \
     "Chrysalide creates an internal glue to provide rich comparisons"   \
     " for operands based on the old-style *__cmp__* function."
 
@@ -165,6 +181,9 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec
 static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unused)
 {
     class->compare = py_arch_operand___cmp___wrapper;
+    class->find_inner = py_arch_operand_find_inner_operand_path_wrapper;
+    class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper;
+
     class->print = py_arch_operand_print_wrapper;
     class->build_tooltip = py_arch_operand_build_tooltip_wrapper;
 
@@ -224,10 +243,154 @@ static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOpe
                 result = PyLong_AsLong(pyret);
         }
 
+        Py_XDECREF(pyret);
+
         Py_DECREF(args);
 
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER PYTHON_WRAPPER_DEF     \
+(                                                                           \
+    _find_inner_operand_path, "$self, target, /",                           \
+    METH_VARARGS,                                                           \
+    "Abstract method used to compute the path leading to an inner"          \
+    " operand.\n"                                                           \
+    "\n"                                                                    \
+    "The *target* has to be an instance of pychrysalide.arch.ArchOperand"   \
+    " included in the operand.\n"                                           \
+    "\n"                                                                    \
+    "The result is a string of the form 'n[:n:n:n]', where n is an"         \
+    " internal index, or None if the *target* is not found. This kind of"   \
+    " path is aimed to be built for the"                                    \
+    " pychrysalide.arch.ArchInstruction.find_operand_path() function."      \
+)
+
+    result = NULL;
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(operand));
+
+    if (has_python_method(pyobj, "_find_inner_operand_path"))
+    {
+        args = PyTuple_New(1);
+        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(target)));
+
+        pyret = run_python_method(pyobj, "_find_inner_operand_path", args);
+
+        if (pyret != NULL)
+        {
+            if (PyUnicode_Check(pyret))
+                result = strdup(PyUnicode_AsUTF8(pyret));
+        }
+
         Py_XDECREF(pyret);
 
+        Py_DECREF(args);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const GArchOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *args;                         /* Arguments pour l'appel      */
+    PyObject *pyret;                        /* Bilan de consultation       */
+
+#define ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER PYTHON_WRAPPER_DEF \
+(                                                                           \
+    _get_inner_operand_from_path, "$self, path, /",                         \
+    METH_VARARGS,                                                           \
+    "Abstract method used to retrieve an inner operand by its path.\n"      \
+    "\n"                                                                    \
+    "This *path* is a string of the form 'n[:n:n:n]', where n is an"        \
+    " internal index. Such a path is usually built by the"                  \
+    " pychrysalide.arch.ArchInstruction.find_operand_path() function.\n"    \
+    "\n"                                                                    \
+    "The result is an pychrysalide.arch.ArchOperand instance, or"           \
+    " None if no operand was found."                                        \
+)
+
+    result = NULL;
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(operand));
+
+    if (has_python_method(pyobj, "_get_inner_operand_from_path"))
+    {
+        args = PyTuple_New(1);
+        PyTuple_SetItem(args, 0, PyUnicode_FromString(path));
+
+        pyret = run_python_method(pyobj, "_get_inner_operand_from_path", args);
+
+        if (pyret != NULL)
+        {
+            if (PyObject_TypeCheck(pyret, get_python_arch_operand_type()))
+            {
+                result = G_ARCH_OPERAND(pygobject_get(pyret));
+                g_object_ref(G_OBJECT(result));
+            }
+
+        }
+
+        Py_XDECREF(pyret);
+
+        Py_DECREF(args);
+
     }
 
     Py_DECREF(pyobj);
@@ -278,10 +441,10 @@ static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLi
 
         pyret = run_python_method(pyobj, "_print", args);
 
-        Py_DECREF(args);
-
         Py_XDECREF(pyret);
 
+        Py_DECREF(args);
+
     }
 
     Py_DECREF(pyobj);
@@ -311,7 +474,6 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand,
     PyObject *pyobj;                        /* Objet Python concerné       */
     PyObject *args;                         /* Arguments pour l'appel      */
     PyObject *pyret;                        /* Bilan de consultation       */
-    int ret;                                /* Bilan d'une conversion      */
 
 #define ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER PYTHON_WRAPPER_DEF       \
 (                                                                   \
@@ -339,15 +501,12 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand,
 
         if (pyret != NULL)
         {
-            ret = PyUnicode_Check(pyret);
-
-            if (ret)
+            if (PyUnicode_Check(pyret))
                 result = strdup(PyUnicode_AsUTF8(pyret));
-
-            Py_DECREF(pyret);
-
         }
 
+        Py_XDECREF(pyret);
+
         Py_DECREF(args);
 
     }
@@ -414,6 +573,123 @@ static PyObject *py_arch_operand_richcompare(PyObject *a, PyObject *b, int op)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = architecture concernée par la procédure.              *
+*                args = instruction représentant le point de départ.          *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou None en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_operand_find_inner_operand_path(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Chemin à retourner          */
+    GArchOperand *target;                   /* Opérande ciblé par l'action */
+    int ret;                                /* Bilan de lecture des args.  */
+    GArchOperand *operand;                  /* Opérande manipulé           */
+    char *path;                             /* Chemin déterminé            */
+
+#define ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD PYTHON_METHOD_DEF       \
+(                                                                           \
+    find_inner_operand_path, "$self, target, /",                            \
+    METH_VARARGS, py_arch_operand,                                          \
+    "Compute the path leading to an inner operand.\n"                       \
+    "\n"                                                                    \
+    "The *target* has to be an instance of pychrysalide.arch.ArchOperand"   \
+    " included in the operand.\n"                                           \
+    "\n"                                                                    \
+    "The result is a string of the form 'n[:n:n:n]', where n is an"         \
+    " internal index, or None if the *target* is not found. This kind of"   \
+    " path is aimed to be built for the"                                    \
+    " pychrysalide.arch.ArchInstruction.find_operand_path() function."      \
+)
+
+    ret = PyArg_ParseTuple(args, "O&", convert_to_arch_operand, &target);
+    if (!ret) return NULL;
+
+    operand = G_ARCH_OPERAND(pygobject_get(self));
+
+    path = g_arch_operand_find_inner_operand_path(operand, target);
+
+    if (path != NULL)
+    {
+        result = PyUnicode_FromString(path);
+        free(path);
+    }
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = architecture concernée par la procédure.              *
+*                args = instruction représentant le point de départ.          *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou None en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_arch_operand_get_inner_operand_from_path(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Trouvaille à retourner      */
+    const char *path;                       /* Chemin à parcourir          */
+    int ret;                                /* Bilan de lecture des args.  */
+    GArchOperand *operand;                  /* Opérande manipulé           */
+    GArchOperand *op;                       /* Opérande retrouvé           */
+
+#define ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD PYTHON_METHOD_DEF   \
+(                                                                           \
+    get_inner_operand_from_path, "$self, path, /",                          \
+    METH_VARARGS, py_arch_operand,                                          \
+    "Retrieve an inner operand by its path.\n"                              \
+    "\n"                                                                    \
+    "This *path* is a string of the form 'n[:n:n:n]', where n is an"        \
+    " internal index. Such a path is usually built by the"                  \
+    " pychrysalide.arch.ArchInstruction.find_operand_path() function.\n"    \
+    "\n"                                                                    \
+    "The result is an pychrysalide.arch.ArchOperand instance, or"           \
+    " None if no operand was found."                                        \
+)
+
+    ret = PyArg_ParseTuple(args, "s", &path);
+    if (!ret) return NULL;
+
+    operand = G_ARCH_OPERAND(pygobject_get(self));
+
+    op = g_arch_operand_get_inner_operand_from_path(operand, path);
+
+    if (op != NULL)
+    {
+        result = pygobject_new(G_OBJECT(op));
+        g_object_unref(G_OBJECT(op));
+    }
+    else
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
 *  Description : Fournit un accès à une définition de type à diffuser.        *
@@ -428,8 +704,12 @@ PyTypeObject *get_python_arch_operand_type(void)
 {
     static PyMethodDef py_arch_operand_methods[] = {
         ARCH_OPERAND_CMP_WRAPPER,
+        ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER,
+        ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER,
         ARCH_OPERAND_PRINT_WRAPPER,
         ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER,
+        ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD,
+        ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD,
         { NULL }
     };
 
diff --git a/src/arch/instruction.c b/src/arch/instruction.c
index ea19dab..52c3aa0 100644
--- a/src/arch/instruction.c
+++ b/src/arch/instruction.c
@@ -27,11 +27,14 @@
 #include <assert.h>
 #include <malloc.h>
 #include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 
 #include "instruction-int.h"
 #include "storage.h"
+#include "../core/logs.h"
 #include "../glibext/gbinarycursor.h"
 #include "../glibext/linegen-int.h"
 #include "../gtkext/gtkblockdisplay.h"
@@ -819,6 +822,146 @@ bool _g_arch_instruction_detach_operand(GArchInstruction *instr, GArchOperand *t
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr  = instance à consulter.                               *
+*                target = instruction à venir retrouver.                      *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande.                *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *g_arch_instruction_find_operand_path(GArchInstruction *instr, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+    size_t count;                           /* Nombre d'opérandes en place */
+    size_t i;                               /* Boucle de parcours          */
+    GArchOperand *op;                       /* Opérande à manipuler        */
+    int ret;                                /* Bilan d'une construction    */
+    char *sub_path;                         /* Sous-chemin emprunté        */
+
+    result = NULL;
+
+    g_arch_instruction_lock_operands(instr);
+
+    count = _g_arch_instruction_count_operands(instr);
+
+    /* Première passe : accès direct */
+
+    for (i = 0; i < count && result == NULL; i++)
+    {
+        op = _g_arch_instruction_get_operand(instr, i);
+
+        if (op == target)
+        {
+            ret = asprintf(&result, "%zu", i);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+        }
+
+        g_object_unref(G_OBJECT(op));
+
+    }
+
+    /* Seconde passe : accès profond */
+
+    for (i = 0; i < count && result == NULL; i++)
+    {
+        op = _g_arch_instruction_get_operand(instr, i);
+
+        sub_path = g_arch_operand_find_inner_operand_path(op, target);
+
+        if (sub_path != NULL)
+        {
+            ret = asprintf(&result, "%zu:%s", i, sub_path);
+            if (ret == -1)
+            {
+                LOG_ERROR_N("asprintf");
+                result = NULL;
+            }
+
+            free(sub_path);
+
+        }
+
+        g_object_unref(G_OBJECT(op));
+
+    }
+
+    g_arch_instruction_unlock_operands(instr);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instance à consulter.                                *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *instr, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+    size_t index;                           /* Indice de l'opérande visé   */
+    char *end;                              /* Poursuite du parcours ?     */
+    GArchOperand *found;                    /* Opérande trouvé             */
+
+    result = NULL;
+
+    g_arch_instruction_lock_operands(instr);
+
+    /* Recherche au premier niveau */
+
+    index = strtoul(path, &end, 10);
+
+    if ((index == ULONG_MAX && errno == ERANGE) || (index == 0 && errno == EINVAL))
+    {
+        LOG_ERROR_N("strtoul");
+        goto done;
+    }
+
+    found = _g_arch_instruction_get_operand(instr, index);
+    if (found == NULL) goto done;
+
+    if (*end == '\0')
+    {
+        result = found;
+        goto done;
+    }
+
+    /* Recherche en profondeur */
+
+    assert(*end == ':');
+
+    result = g_arch_operand_get_inner_operand_from_path(found, end + 1);
+
+    g_object_unref(G_OBJECT(found));
+
+ done:
+
+    g_arch_instruction_unlock_operands(instr);
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                     DEFINITION DES LIAISONS ENTRE INSTRUCTIONS                     */
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index e8ba4bd..0401853 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -208,6 +208,13 @@ bool _g_arch_instruction_detach_operand(GArchInstruction *, GArchOperand *);
     })
 
 
+/* Détermine le chemin conduisant à un opérande. */
+char *g_arch_instruction_find_operand_path(GArchInstruction *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+GArchOperand *g_arch_instruction_get_operand_from_path(GArchInstruction *, const char *);
+
+
 
 /* ------------------- DEFINITION DES LIAISONS ENTRE INSTRUCTIONS ------------------- */
 
diff --git a/src/arch/operand-int.h b/src/arch/operand-int.h
index 4cc676e..b019ac1 100644
--- a/src/arch/operand-int.h
+++ b/src/arch/operand-int.h
@@ -32,6 +32,12 @@
 /* Compare un opérande avec un autre. */
 typedef int (* operand_compare_fc) (const GArchOperand *, const GArchOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+typedef char * (* find_inner_operand_fc) (const GArchOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+typedef GArchOperand * (* get_inner_operand_fc) (const GArchOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 typedef void (* operand_print_fc) (const GArchOperand *, GBufferLine *);
 
@@ -59,6 +65,9 @@ struct _GArchOperandClass
     GObjectClass parent;                    /* A laisser en premier        */
 
     operand_compare_fc compare;             /* Comparaison d'opérandes     */
+    find_inner_operand_fc find_inner;       /* Définition d'un chemin      */
+    get_inner_operand_fc get_inner;         /* Récupération d'un opérande  */
+
     operand_print_fc print;                 /* Texte humain équivalent     */
     operand_build_tooltip_fc build_tooltip; /* Construction de description */
 
diff --git a/src/arch/operand.c b/src/arch/operand.c
index 237cc76..92fb1d6 100644
--- a/src/arch/operand.c
+++ b/src/arch/operand.c
@@ -193,6 +193,68 @@ int g_arch_operand_compare(const GArchOperand *a, const GArchOperand *b)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                target  = instruction à venir retrouver.                     *
+*                                                                             *
+*  Description : Détermine le chemin conduisant à un opérande interne.        *
+*                                                                             *
+*  Retour      : Chemin d'accès à l'opérande ou NULL en cas d'absence.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *g_arch_operand_find_inner_operand_path(const GArchOperand *operand, const GArchOperand *target)
+{
+    char *result;                           /* Chemin à retourner          */
+    GArchOperandClass *class;               /* Classe associée à l'objet   */
+
+    class = G_ARCH_OPERAND_GET_CLASS(operand);
+
+    if (class->find_inner != NULL)
+        result = class->find_inner(operand, target);
+
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : operand = opérande à consulter.                              *
+*                path  = chemin d'accès à un opérande à retrouver.            *
+*                                                                             *
+*  Description : Obtient l'opérande correspondant à un chemin donné.          *
+*                                                                             *
+*  Retour      : Opérande trouvé ou NULL en cas d'échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *operand, const char *path)
+{
+    GArchOperand *result;                   /* Opérande trouvée à renvoyer */
+    GArchOperandClass *class;               /* Classe associée à l'objet   */
+
+    class = G_ARCH_OPERAND_GET_CLASS(operand);
+
+    if (class->get_inner != NULL)
+        result = class->get_inner(operand, path);
+
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : operand = opérande à traiter.                                *
 *                line    = ligne tampon où imprimer l'opérande donné.         *
 *                                                                             *
diff --git a/src/arch/operand.h b/src/arch/operand.h
index faeab49..4d3a80a 100644
--- a/src/arch/operand.h
+++ b/src/arch/operand.h
@@ -62,6 +62,12 @@ GType g_arch_operand_get_type(void);
 /* Compare un opérande avec un autre. */
 int g_arch_operand_compare(const GArchOperand *, const GArchOperand *);
 
+/* Détermine le chemin conduisant à un opérande interne. */
+char *g_arch_operand_find_inner_operand_path(const GArchOperand *, const GArchOperand *);
+
+/* Obtient l'opérande correspondant à un chemin donné. */
+GArchOperand *g_arch_operand_get_inner_operand_from_path(const GArchOperand *, const char *);
+
 /* Traduit un opérande en version humainement lisible. */
 void g_arch_operand_print(const GArchOperand *, GBufferLine *);
 
-- 
cgit v0.11.2-87-g4458