From 378be1ab322dce8e8377d692829d6877758e5960 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 17 Jun 2018 18:11:45 +0200
Subject: Annotated linux kernel syscalls using a new plugin.

---
 configure.ac                          |   1 +
 plugins/Makefile.am                   |   2 +-
 plugins/lnxsyscalls/Makefile.am       |  39 +++
 plugins/lnxsyscalls/collect.c         | 643 ++++++++++++++++++++++++++++++++++
 plugins/lnxsyscalls/collect.h         |  63 ++++
 plugins/lnxsyscalls/core.c            | 168 +++++++++
 plugins/lnxsyscalls/core.h            |  41 +++
 plugins/lnxsyscalls/db.c              | 245 +++++++++++++
 plugins/lnxsyscalls/db.h              |  52 +++
 plugins/lnxsyscalls/hops.h            |  67 ++++
 plugins/lnxsyscalls/hops_armv7.c      | 262 ++++++++++++++
 plugins/lnxsyscalls/hops_armv7.h      |  37 ++
 plugins/lnxsyscalls/hunter.c          | 346 ++++++++++++++++++
 plugins/lnxsyscalls/hunter.h          |  56 +++
 plugins/lnxsyscalls/linux-syscalls.db | Bin 0 -> 49152 bytes
 plugins/lnxsyscalls/syscall.c         | 108 ++++++
 plugins/lnxsyscalls/syscall.h         |  58 +++
 plugins/lnxsyscalls/writer.c          | 222 ++++++++++++
 plugins/lnxsyscalls/writer.h          |  50 +++
 src/arch/instriter.c                  |  35 ++
 src/arch/instriter.h                  |   3 +
 src/core/paths.c                      |   4 +-
 22 files changed, 2499 insertions(+), 3 deletions(-)
 create mode 100644 plugins/lnxsyscalls/Makefile.am
 create mode 100644 plugins/lnxsyscalls/collect.c
 create mode 100644 plugins/lnxsyscalls/collect.h
 create mode 100644 plugins/lnxsyscalls/core.c
 create mode 100644 plugins/lnxsyscalls/core.h
 create mode 100644 plugins/lnxsyscalls/db.c
 create mode 100644 plugins/lnxsyscalls/db.h
 create mode 100644 plugins/lnxsyscalls/hops.h
 create mode 100644 plugins/lnxsyscalls/hops_armv7.c
 create mode 100644 plugins/lnxsyscalls/hops_armv7.h
 create mode 100644 plugins/lnxsyscalls/hunter.c
 create mode 100644 plugins/lnxsyscalls/hunter.h
 create mode 100644 plugins/lnxsyscalls/linux-syscalls.db
 create mode 100644 plugins/lnxsyscalls/syscall.c
 create mode 100644 plugins/lnxsyscalls/syscall.h
 create mode 100644 plugins/lnxsyscalls/writer.c
 create mode 100644 plugins/lnxsyscalls/writer.h

diff --git a/configure.ac b/configure.ac
index 3bb72c3..cdaa458 100644
--- a/configure.ac
+++ b/configure.ac
@@ -354,6 +354,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/elf/python/Makefile
                  plugins/fmtp/Makefile
                  plugins/libcsem/Makefile
+                 plugins/lnxsyscalls/Makefile
                  plugins/mobicore/Makefile
                  plugins/pychrysalide/Makefile
                  plugins/pychrysalide/analysis/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 25774db..90556de 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -4,4 +4,4 @@ if HAVE_PYTHON3_CONFIG
 endif
 
 # androhelpers
-SUBDIRS = arm dalvik devdbg dex dexbnf elf fmtp libcsem mobicore $(PYTHON3_SUBDIRS) readdex readelf readmc ropgadgets
+SUBDIRS = arm dalvik devdbg dex dexbnf elf fmtp libcsem lnxsyscalls mobicore $(PYTHON3_SUBDIRS) readdex readelf readmc ropgadgets
diff --git a/plugins/lnxsyscalls/Makefile.am b/plugins/lnxsyscalls/Makefile.am
new file mode 100644
index 0000000..251c1c9
--- /dev/null
+++ b/plugins/lnxsyscalls/Makefile.am
@@ -0,0 +1,39 @@
+
+lib_LTLIBRARIES = liblnxsyscalls.la
+
+libdir = $(pluginsdir)
+
+
+liblnxsyscalls_la_SOURCES =				\
+	collect.h collect.c					\
+	core.h core.c						\
+	db.h db.c							\
+	hops.h								\
+	hops_armv7.h hops_armv7.c			\
+	hunter.h hunter.c					\
+	syscall.h syscall.c					\
+	writer.h writer.c
+
+liblnxsyscalls_la_CFLAGS = $(AM_CFLAGS)
+
+liblnxsyscalls_la_LIBADD = 
+
+liblnxsyscalls_la_LDFLAGS = $(LIBPYTHON_LIBS) $(LIBPYGOBJECT_LIBS) \
+	-L$(top_srcdir)/src/.libs -lchrysacore
+
+
+db_DATA = linux-syscalls.db
+
+dbdir = $(pluginsdir)
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(liblnxsyscalls_la_SOURCES:%c=)
+
+
+AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS)
+
+SUBDIRS = 
diff --git a/plugins/lnxsyscalls/collect.c b/plugins/lnxsyscalls/collect.c
new file mode 100644
index 0000000..a71e833
--- /dev/null
+++ b/plugins/lnxsyscalls/collect.c
@@ -0,0 +1,643 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collect.c - collecte de différents registres en remontant le flot d'exécution
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "collect.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <arch/operands/register.h>
+
+
+#include "hops.h"
+
+
+
+/* Suivi de l'usage d'un registre */
+typedef struct _collected_register
+{
+    GArchRegister *reg;                     /* Registre usité à tracer     */
+
+    bool required;                          /* Registre utile ?            */
+
+    GArchInstruction *written;              /* Emplacement d'écriture      */
+
+} collected_register;
+
+/* Suivi d'un flot d'exécution */
+typedef struct _call_stack
+{
+    collected_register *registers;          /* Liste de registres suivis   */
+    size_t count;                           /* Taille de cette liste       */
+
+    instr_iter_t *iter;                     /* Boucle de parcours          */
+    bool use_current;                       /* Traite l'instruction pointée*/
+
+    bool skip_syscall;                      /* Acceptation des rencontres  */
+
+} call_stack;
+
+/* Collection de registres */
+struct _tracked_path
+{
+    call_stack *stacks;                     /* Piles d'exécution suivies   */
+    size_t count;                           /* Nombre de ces piles         */
+
+};
+
+
+/* Copie les informations de pile d'appels. */
+static void copy_call_stack(call_stack *, const call_stack *);
+
+/* Libère la mémoire des infos relatives à une pile d'appels. */
+static void clean_call_stack(call_stack *);
+
+/* Fournit une structure de suivi de registres pour une branche. */
+static size_t fork_register_tracker(tracked_path *, size_t, GArchProcessor *, GArchInstruction *);
+
+/* Change la tête de lecture pour le parcours des instructions. */
+static void change_register_tracker_iter(tracked_path *, size_t, GArchProcessor *, GArchInstruction *);
+
+/* Détermine si tous les registres recherchés ont été trouvés. */
+static bool got_all_tracked_registers(const tracked_path *, size_t);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dest = zone de destination des données copiées. [OUT]        *
+*                src  = source des données à copier.                          *
+*                                                                             *
+*  Description : Copie les informations de pile d'appels.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void copy_call_stack(call_stack *dest, const call_stack *src)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    if (src->count == 0)
+    {
+        dest->registers = NULL;
+        dest->count = 0;
+    }
+
+    else
+    {
+        dest->registers = (collected_register *)malloc(src->count * sizeof(collected_register));
+        dest->count = src->count;
+
+        for (i = 0; i < src->count; i++)
+        {
+            dest->registers[i].reg = src->registers[i].reg;
+            dest->registers[i].required = src->registers[i].required;
+            dest->registers[i].written = src->registers[i].written;
+
+            g_object_ref(G_OBJECT(dest->registers[i].reg));
+
+            if (dest->registers[i].written != NULL)
+                g_object_ref(G_OBJECT(dest->registers[i].written));
+
+        }
+
+    }
+
+    dest->iter = copy_instruction_iterator(src->iter);
+    dest->use_current = src->use_current;
+
+    dest->skip_syscall = src->skip_syscall;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : stack = information sur une pile d'appels à supprimer.       *
+*                                                                             *
+*  Description : Libère la mémoire des infos relatives à une pile d'appels.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void clean_call_stack(call_stack *stack)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < stack->count; i++)
+    {
+        g_object_unref(G_OBJECT(stack->registers[i].reg));
+
+        if (stack->registers[i].written != NULL)
+            g_object_unref(G_OBJECT(stack->registers[i].written));
+
+    }
+
+    if (stack->registers != NULL)
+        free(stack->registers);
+
+    if (stack->iter != NULL)
+        delete_instruction_iterator(stack->iter);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : base = position de parcours initiale.                        *
+*                                                                             *
+*  Description : Crée une structure de suivi de registres vide.               *
+*                                                                             *
+*  Retour      : Structure prête à emploi.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+tracked_path *create_register_tracker(instr_iter_t *base)
+{
+    tracked_path *result;                   /* Structure à retourner       */
+
+    result = (tracked_path *)malloc(sizeof(tracked_path));
+
+    result->stacks = (call_stack *)malloc(sizeof(call_stack));
+    result->count = 1;
+
+    copy_call_stack(&result->stacks[0],
+                    (call_stack []) {
+                        {
+                            .count = 0,
+                            .iter = base,
+                            .use_current = true,
+                            .skip_syscall = true
+                        }
+                    });
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : model = suivi déjà en place d'où l'inspiration doit venir.   *
+*                sid   = identifiant de la pile d'exécution initiale.         *
+*                                                                             *
+*  Description : Crée une structure de suivi de registres initialisée.        *
+*                                                                             *
+*  Retour      : Structure prête à emploi.                                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+tracked_path *create_register_tracker_from(const tracked_path *model, size_t sid)
+{
+    tracked_path *result;                   /* Structure à retourner       */
+
+    result = (tracked_path *)malloc(sizeof(tracked_path));
+
+    result->stacks = (call_stack *)malloc(sizeof(call_stack));
+    result->count = 1;
+
+    copy_call_stack(&result->stacks[0], &model->stacks[sid]);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à traiter.                         *
+*                                                                             *
+*  Description : Efface une structure de suivi de registres.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void delete_register_tracker(tracked_path *path)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    assert(path->count >= 1);
+
+    for (i = 0; i < path->count; i++)
+        clean_call_stack(&path->stacks[i]);
+
+    free(path->stacks);
+
+    free(path);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à consulter.                       *
+*                                                                             *
+*  Description : Dénombre les piles d'exécutions différentes conservées.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t count_register_tracker_stacks(const tracked_path *path)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    result = path->count;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à traiter.                         *
+*                sid  = identifiant de la pile d'exécution racine à copier.   *
+*                proc = processeur de l'architecture pour les instructions.   *
+*                dest = prochaine instruction à traiter.                      *
+*                                                                             *
+*  Description : Fournit une structure de suivi de registres pour une branche.*
+*                                                                             *
+*  Retour      : Indice de la nouvelle pile d'exécution à suivre.             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static size_t fork_register_tracker(tracked_path *path, size_t sid, GArchProcessor *proc, GArchInstruction *dest)
+{
+    size_t result;                          /* Indice à retourner          */
+
+    result = path->count;
+
+    path->stacks = (call_stack *)realloc(path->stacks, ++path->count * sizeof(call_stack));
+
+    copy_call_stack(&path->stacks[result], &path->stacks[sid]);
+
+    change_register_tracker_iter(path, result, proc, dest);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à traiter.                         *
+*                sid  = identifiant de la pile d'exécution à traiter.         *
+*                proc = processeur de l'architecture pour les instructions.   *
+*                dest = prochaine instruction à traiter.                      *
+*                                                                             *
+*  Description : Change la tête de lecture pour le parcours des instructions. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void change_register_tracker_iter(tracked_path *path, size_t sid, GArchProcessor *proc, GArchInstruction *dest)
+{
+    const mrange_t *range;                  /* Couverture d'une instruction*/
+    instr_iter_t *iter;                     /* Tête de lecture             */
+
+    delete_instruction_iterator(path->stacks[sid].iter);
+
+    range = g_arch_instruction_get_range(dest);
+    iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(range));
+
+    path->stacks[sid].iter = iter;
+    path->stacks[sid].use_current = true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path  = chemin d'exécution à traiter.                        *
+*                sid   = identifiant de la pile d'exécution à traiter.        *
+*                reg   = registre concerné par la procédure.                  *
+*                where = localisation de l'écriture ou importance de la note. *
+*                                                                             *
+*  Description : Note le besoin ou l'usage d'un registre donné.               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void mark_register_in_tracker(tracked_path *path, size_t sid, GArchRegister *reg, GArchInstruction *where)
+{
+    call_stack *stack;                      /* Pile d'exécution concernée  */
+    size_t i;                               /* Boucle de parcours          */
+    collected_register *collected;          /* Accès simplifié             */
+    int ret;                                /* Bilan d'une comparaison     */
+
+    stack = &path->stacks[sid];
+
+    /* Mise à jour d'un élément présent ? */
+
+    for (i = 0; i < stack->count; i++)
+    {
+        collected = &stack->registers[i];
+
+        ret = g_arch_register_compare(collected->reg, reg);
+        if (ret != 0) continue;
+
+        if (where == NULL)
+            collected->required = true;
+
+        else
+        {
+            if (collected->written == NULL)
+            {
+                collected->written = where;
+                g_object_ref(G_OBJECT(where));
+            }
+
+        }
+
+        break;
+
+    }
+
+    /* Ajout d'une nouvelle note */
+
+    if (i == stack->count)
+    {
+        stack->count++;
+        stack->registers = (collected_register *)realloc(stack->registers,
+                                                         stack->count * sizeof(collected_register));
+
+        collected = &stack->registers[stack->count - 1];
+
+        collected->reg = reg;
+        g_object_ref(G_OBJECT(reg));
+
+        if (where == NULL)
+        {
+            collected->required = true;
+            collected->written = NULL;
+        }
+
+        else
+        {
+            collected->required = false;
+            collected->written = where;
+            g_object_ref(G_OBJECT(where));
+        }
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à consulter.                       *
+*                sid   = identifiant de la pile d'exécution à traiter.        *
+*                                                                             *
+*  Description : Détermine si tous les registres recherchés ont été trouvés.  *
+*                                                                             *
+*  Retour      : Besoin en poursuite d'études.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool got_all_tracked_registers(const tracked_path *path, size_t sid)
+{
+    bool result;                            /* Bilan à retourner           */
+    call_stack *stack;                      /* Pile d'exécution concernée  */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+
+    stack = &path->stacks[sid];
+
+    for (i = 0; i < stack->count && result; i++)
+        if (stack->registers[i].required)
+            result = (stack->registers[i].written != NULL);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à consulter et compléter.          *
+*                sid  = identifiant de la pile d'exécution à traiter.         *
+*                proc = processeur de l'architecture pour les instructions.   *
+*                hops = opérations spécialement adaptées à une architecture.  *
+*                                                                             *
+*  Description : Se lance à la recherche de la définition de registres.       *
+*                                                                             *
+*  Retour      : true si toutes les définitions demandées ont été trouvées.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool look_for_registers(tracked_path *path, size_t sid, GArchProcessor *proc, const hunting_ops *hops)
+{
+    bool result;                            /* Bilan de l'opération        */
+    call_stack *stack;                      /* Pile d'exécution concernée  */
+    GArchInstruction *instr;                /* Instruction analysée        */
+    GArchOperand *operand;                  /* Destination d'instruction ? */
+    GArchRegister *reg;                     /* Registre en première ligne  */
+    size_t count;                           /* Nombre de sources présentes */
+    bool first;                             /* Premier aiguillage ?        */
+    size_t i;                               /* Boucle de parcours          */
+    instr_link_t *link;                     /* Détails d'un lien           */
+    size_t next;                            /* Indice de la pile suivante  */
+
+    stack = &path->stacks[sid];
+
+    while (stack->iter != NULL && !got_all_tracked_registers(path, sid))
+    {
+        if (stack->use_current)
+        {
+            instr = get_instruction_iterator_current(stack->iter);
+            stack->use_current = false;
+        }
+
+        else
+            instr = get_instruction_iterator_prev(stack->iter);
+
+        /* Détection de fin de parcours (#1) */
+
+        if (instr == NULL)
+        {
+            delete_instruction_iterator(stack->iter);
+            stack->iter = NULL;
+            break;
+        }
+
+        if (hops->is_syscall(instr) && !stack->skip_syscall)
+        {
+            delete_instruction_iterator(stack->iter);
+            stack->iter = NULL;
+            break;
+        }
+
+        stack->skip_syscall = false;
+
+        /* Traitement de l'instruction courante */
+
+        operand = g_arch_instruction_get_operand(instr, 0);
+
+        if (G_IS_REGISTER_OPERAND(operand))
+        {
+            reg = g_register_operand_get_register(G_REGISTER_OPERAND(operand));
+
+            mark_register_in_tracker(path, sid, reg, instr);
+
+        }
+
+        /* Détermination de l'instruction suivante */
+
+        g_arch_instruction_lock_src(instr);
+
+        count = g_arch_instruction_count_sources(instr);
+
+        first = true;
+
+        for (i = 0; i < count; i++)
+        {
+            link = g_arch_instruction_get_source(instr, i);
+
+            switch (link->type)
+            {
+                case ILT_EXEC_FLOW:
+                case ILT_JUMP:
+                case ILT_CASE_JUMP:
+                case ILT_JUMP_IF_TRUE:
+                case ILT_JUMP_IF_FALSE:
+                case ILT_LOOP:
+
+                    if (first)
+                    {
+                        change_register_tracker_iter(path, sid, proc, link->linked);
+                        first = false;
+                    }
+
+                    else
+                    {
+                        next = fork_register_tracker(path, sid, proc, link->linked);
+                        look_for_registers(path, next, proc, hops);
+                    }
+
+                    break;
+
+                default:
+                    break;
+
+            }
+
+        }
+
+        g_arch_instruction_unlock_src(instr);
+
+        /* Détection de fin de parcours (#2) */
+
+        if (g_arch_instruction_get_flags(instr) & AIF_ROUTINE_START)
+        {
+            delete_instruction_iterator(stack->iter);
+            stack->iter = NULL;
+            break;
+        }
+
+    }
+
+    result = got_all_tracked_registers(path, sid);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'exécution à traiter.                         *
+*                sid   = identifiant de la pile d'exécution à traiter.        *
+*                reg  = registre concerné par la procédure.                   *
+*                                                                             *
+*  Description : Retrouve la dernière modification d'un registre donné.       *
+*                                                                             *
+*  Retour      : Localisation de l'écriture ou importante de la note.         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GArchInstruction *get_register_write_location(const tracked_path *path, size_t sid, const GArchRegister *reg)
+{
+    GArchInstruction *result;               /* Emplacement à retourner     */
+    call_stack *stack;                      /* Pile d'exécution concernée  */
+    size_t i;                               /* Boucle de parcours          */
+    collected_register *collected;          /* Accès simplifié             */
+    int ret;                                /* Bilan d'une comparaison     */
+
+    result = NULL;
+
+    stack = &path->stacks[sid];
+
+    for (i = 0; i < stack->count; i++)
+    {
+        collected = &stack->registers[i];
+
+        ret = g_arch_register_compare(collected->reg, reg);
+        if (ret != 0) continue;
+
+        result = collected->written;
+
+        if (result != NULL)
+            g_object_ref(G_OBJECT(result));
+
+        break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/lnxsyscalls/collect.h b/plugins/lnxsyscalls/collect.h
new file mode 100644
index 0000000..370c27e
--- /dev/null
+++ b/plugins/lnxsyscalls/collect.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collect.h - prototypes pour la collecte de différents registres en remontant le flot d'exécution
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_COLLECT_H
+#define _PLUGINS_LNXSYSCALLS_COLLECT_H
+
+
+#include <arch/instriter.h>
+#include <arch/register.h>
+
+
+
+/* Depuis hops.h : opérations adaptées pour une chasse donnée */
+typedef struct _hunting_ops hunting_ops;
+
+/* Collection de registres */
+typedef struct _tracked_path tracked_path;
+
+
+/* Crée une structure de suivi de registres vide. */
+tracked_path *create_register_tracker(instr_iter_t *);
+
+/* Crée une structure de suivi de registres initialisée. */
+tracked_path *create_register_tracker_from(const tracked_path *, size_t);
+
+/* Efface une structure de suivi de registres. */
+void delete_register_tracker(tracked_path *);
+
+/* Dénombre les piles d'exécutions différentes conservées. */
+size_t count_register_tracker_stacks(const tracked_path *);
+
+/* Note le besoin ou l'usage d'un registre donné. */
+void mark_register_in_tracker(tracked_path *, size_t, GArchRegister *, GArchInstruction *);
+
+/* Se lance à la recherche de la définition de registres. */
+bool look_for_registers(tracked_path *, size_t, GArchProcessor *, const hunting_ops *);
+
+/* Retrouve la dernière modification d'un registre donné. */
+GArchInstruction *get_register_write_location(const tracked_path *, size_t, const GArchRegister *);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_COLLECT_H */
diff --git a/plugins/lnxsyscalls/core.c b/plugins/lnxsyscalls/core.c
new file mode 100644
index 0000000..f28e776
--- /dev/null
+++ b/plugins/lnxsyscalls/core.c
@@ -0,0 +1,168 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.c - greffon détaillant les appels système
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "core.h"
+
+
+#include <i18n.h>
+
+
+#include <core/global.h>
+#include <core/nproc.h>
+
+
+#include "db.h"
+#include "hops_armv7.h"
+#include "hunter.h"
+
+
+
+DEFINE_CHRYSALIDE_PLUGIN("Linux System Calls", "Describes each Linux system call with its arguments", \
+                         "0.1.0", EMPTY_PG_LIST(.required), AL(PGA_PLUGIN_INIT, PGA_DISASSEMBLY_ENDED));
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Prend acte du chargement du greffon.                         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin)
+{
+    bool result;                            /* Bilan à retourner           */
+    sqlite3 *db;                            /* Base de données présente    */
+
+    db = open_syscalls_database(plugin);
+
+    if (db != NULL)
+    {
+        introduce_syscalls_database(db, plugin);
+
+        close_syscalls_database(db);
+
+        result = true;
+
+    }
+
+    else
+        result = false;
+
+    return result;
+
+}
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin  = greffon à manipuler.                               *
+*                action  = type d'action attendue.                            *
+*                binary  = binaire dont le contenu est en cours de traitement.*
+*                status  = barre de statut à tenir informée.                  *
+*                context = contexte de désassemblage.                         *
+*                                                                             *
+*  Description : Exécute une action pendant un désassemblage de binaire.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+G_MODULE_EXPORT void process_binary_disassembly(const GPluginModule *plugin, PluginAction action, GLoadedBinary *binary, GtkStatusStack *status, GProcContext *context)
+{
+    GBinFormat *format;                     /* Format du binaire chargé    */
+    const char *arch;                       /* Architecture d'exécution    */
+    const hunting_ops *hops;                /* Opérations particulières    */
+    size_t sym_count;                       /* Nombre de ces symboles      */
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    size_t run_size;                        /* Volume réparti par exécution*/
+    activity_id_t id;                       /* Identifiant de progression  */
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    wgroup_id_t gid;                        /* Identifiant pour les tâches */
+    guint i;                                /* Boucle de parcours          */
+    size_t begin;                           /* Début de bloc de traitement */
+    size_t end;                             /* Fin d'un bloc de traitement */
+    GGateHunter *hunter;                    /* Tâche d'étude à programmer  */
+
+    format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+    arch = g_exe_format_get_target_machine(G_EXE_FORMAT(format));
+
+    if (strcmp(arch, "armv7") == 0)
+        hops = get_armv7_hunting_ops();
+
+    else
+    {
+        g_plugin_module_log_variadic_message(plugin, LMT_WARNING,
+                                             _("No suitable backend to track syscalls!"));
+        goto pbd_exit;
+    }
+
+    g_binary_format_lock_symbols_rd(format);
+
+    sym_count = g_binary_format_count_symbols(format);
+
+    runs_count = get_max_online_threads();
+
+    run_size = sym_count / runs_count;
+
+    id = gtk_status_stack_add_activity(status, _("Looking for Linux syscalls..."), sym_count);
+
+    queue = get_work_queue();
+
+    gid = g_work_queue_define_work_group(queue);
+
+    for (i = 0; i < runs_count; i++)
+    {
+        begin = i * run_size;
+
+        if ((i + 1) == runs_count)
+            end = sym_count;
+        else
+            end = begin + run_size;
+
+        hunter = g_gate_hunter_new(plugin, binary, context, begin, end, id, hops);
+
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(hunter), gid);
+
+    }
+
+    g_work_queue_wait_for_completion(queue, gid);
+
+    g_work_queue_delete_work_group(queue, gid);
+
+    gtk_status_stack_remove_activity(status, id);
+
+    g_binary_format_unlock_symbols_rd(format);
+
+ pbd_exit:
+
+    g_object_unref(G_OBJECT(format));
+
+}
diff --git a/plugins/lnxsyscalls/core.h b/plugins/lnxsyscalls/core.h
new file mode 100644
index 0000000..a8e987e
--- /dev/null
+++ b/plugins/lnxsyscalls/core.h
@@ -0,0 +1,41 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * core.h - prototypes pour le greffon détaillant les appels système
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_CORE_H
+#define _PLUGINS_LNXSYSCALLS_CORE_H
+
+
+#include <plugins/plugin.h>
+#include <plugins/plugin-int.h>
+
+
+
+/* Prend acte du chargement du greffon. */
+G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *);
+
+/* Exécute une action pendant un désassemblage de binaire. */
+G_MODULE_EXPORT void process_binary_disassembly(const GPluginModule *, PluginAction , GLoadedBinary *, GtkStatusStack *, GProcContext *);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_CORE_H */
diff --git a/plugins/lnxsyscalls/db.c b/plugins/lnxsyscalls/db.c
new file mode 100644
index 0000000..d6325b5
--- /dev/null
+++ b/plugins/lnxsyscalls/db.c
@@ -0,0 +1,245 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * db.c - constitution d'identités d'appels depuis une base de données
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "db.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include <i18n.h>
+
+
+#include <core/paths.h>
+#include <plugins/plugin-int.h>
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Ouvre la base de connaissances quant aux appels système.     *
+*                                                                             *
+*  Retour      : Base de données SQLite disponible ou NULL en cas d'échec.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+sqlite3 *open_syscalls_database(const GPluginModule *plugin)
+{
+    sqlite3 *result;                    /* Base de données à renvoyer  */
+    char *filename;                     /* Chemin vers la base         */
+    int ret;                            /* Bilan d'un appel            */
+
+    filename = find_plugin_file("lnxsyscalls", "linux-syscalls.db");
+
+    if (filename == NULL)
+    {
+        g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("Unable to find the syscalls database"));
+        result = NULL;
+    }
+
+    else
+    {
+        ret = sqlite3_open(filename, &result);
+
+        if (ret != SQLITE_OK)
+        {
+            g_plugin_module_log_simple_message(plugin, LMT_ERROR, _("Unable to load the syscalls database"));
+            result = NULL;
+        }
+
+        free(filename);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : db = base de données SQLite à clôturer.                      *
+*                                                                             *
+*  Description : Ferme la base de connaissances quant aux appels système.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void close_syscalls_database(sqlite3 *db)
+{
+#ifndef NDEBUG
+    int ret;                            /* Bilan d'un appel            */
+#endif
+
+#ifndef NDEBUG
+
+    ret = sqlite3_close(db);
+    assert(ret == SQLITE_OK);
+
+#else
+
+    sqlite3_close(db);
+
+#endif
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : db     = base de données SQLite à consulter.                 *
+*                plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Présente le contenu de la base des appels système.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void introduce_syscalls_database(sqlite3 *db, const GPluginModule *plugin)
+{
+    const char *sql;                        /* Requête SQL à construire    */
+    sqlite3_stmt *stmt;                     /* Déclaration mise en place   */
+    int ret;                                /* Bilan d'un appel à SQLite   */
+
+    sql = "SELECT arch, COUNT(nr) FROM Syscalls GROUP BY arch ORDER BY arch;";
+
+	ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+	if (ret != SQLITE_OK)
+    {
+        g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                             _("Can't prepare statment '%s' (ret=%d): %s"),
+                                             sql, ret, sqlite3_errmsg(db));
+        goto isd_exit;
+	}
+
+    for (ret = sqlite3_step(stmt); ret == SQLITE_ROW; ret = sqlite3_step(stmt))
+    {
+        g_plugin_module_log_variadic_message(plugin, LMT_INFO,
+                                             _("The database contains %d syscalls for the '%s' architecture"),
+                                             sqlite3_column_int(stmt, 1),
+                                             (char *)sqlite3_column_text(stmt, 0));
+    }
+
+    sqlite3_finalize(stmt);
+
+ isd_exit:
+
+    ;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : db     = base de données SQLite à consulter.                 *
+*                plugin = greffon à manipuler.                                *
+*                arch   = architecture visée par la procédure.                *
+*              : nr     = indice de l'appel système à décrire.                *
+*                                                                             *
+*  Description : Construit l'identité d'un appel système pour un indice donné.*
+*                                                                             *
+*  Retour      : Structure mise en place ou NULL en cas d'échec.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+syscall_info_t *extract_from_syscalls_database(sqlite3 *db, const GPluginModule *plugin, const char *arch, unsigned int nr)
+{
+    syscall_info_t *result;                 /* Description à retourner     */
+    const char *sql;                        /* Requête SQL à construire    */
+    size_t i;                               /* Boucle de parcours          */
+    sqlite3_stmt *stmt;                     /* Déclaration mise en place   */
+    int ret;                                /* Bilan d'un appel à SQLite   */
+    const char *arg;                        /* Eventuel argument d'appel   */
+
+    result = NULL;
+
+    sql = "SELECT name, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, filename, line" \
+        " FROM Syscalls" \
+        " WHERE arch = ? AND nr = ?;";
+
+	ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+	if (ret != SQLITE_OK)
+    {
+        g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                             _("Can't prepare statment '%s' (ret=%d): %s"),
+                                             sql, ret, sqlite3_errmsg(db));
+        goto efsd_exit;
+	}
+
+    ret = sqlite3_bind_text(stmt, 1, arch, -1, NULL);
+    if (ret != SQLITE_OK)
+    {
+        g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                             _("Can't bind value for parameter nb 0 in '%s' (ret=%d): %s"),
+                                             sql, ret, sqlite3_errmsg(db));
+        goto efsd_clean_exit;
+    }
+
+    ret = sqlite3_bind_int(stmt, 2, nr);
+    if (ret != SQLITE_OK)
+    {
+        g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                             _("Can't bind value for parameter nb 1 in '%s' (ret=%d): %s"),
+                                             sql, ret, sqlite3_errmsg(db));
+        goto efsd_clean_exit;
+    }
+
+    ret = sqlite3_step(stmt);
+
+    if (ret == SQLITE_ROW)
+    {
+        result = create_syscall_info(nr, (char *)sqlite3_column_text(stmt, 0));
+
+        for (i = 0; i < 6; i++)
+        {
+            arg = (char *)sqlite3_column_text(stmt, 1 + i);
+
+            if (arg != NULL)
+                append_arg_to_syscall_info(result, arg);
+
+        }
+
+    }
+
+ efsd_clean_exit:
+
+    sqlite3_finalize(stmt);
+
+ efsd_exit:
+
+    return result;
+
+}
diff --git a/plugins/lnxsyscalls/db.h b/plugins/lnxsyscalls/db.h
new file mode 100644
index 0000000..7eae005
--- /dev/null
+++ b/plugins/lnxsyscalls/db.h
@@ -0,0 +1,52 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * db.h - prototypes pour la constitution d'identités d'appels depuis une base de données
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_DB_H
+#define _PLUGINS_LNXSYSCALLS_DB_H
+
+
+#include <sqlite3.h>
+
+
+#include <plugins/plugin.h>
+
+
+#include "syscall.h"
+
+
+
+/* Ouvre la base de connaissances quant aux appels système. */
+sqlite3 *open_syscalls_database(const GPluginModule *);
+
+/* Ferme la base de connaissances quant aux appels système. */
+void close_syscalls_database(sqlite3 *);
+
+/* Présente le contenu de la base des appels système. */
+void introduce_syscalls_database(sqlite3 *, const GPluginModule *);
+
+/* Construit l'identité d'un appel système pour un indice donné. */
+syscall_info_t *extract_from_syscalls_database(sqlite3 *, const GPluginModule *, const char *, unsigned int);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_DB_H */
diff --git a/plugins/lnxsyscalls/hops.h b/plugins/lnxsyscalls/hops.h
new file mode 100644
index 0000000..42f2cc6
--- /dev/null
+++ b/plugins/lnxsyscalls/hops.h
@@ -0,0 +1,67 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hops.h - prototypes pour les particularités de chasse propres à une architecture
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_HOPS_H
+#define _PLUGINS_LNXSYSCALLS_HOPS_H
+
+
+#include <stdbool.h>
+
+
+#include <arch/processor.h>
+
+
+#include "collect.h"
+#include "syscall.h"
+#include "writer.h"
+
+
+
+/* Détermine si l'instruction lance un appel syystème. */
+typedef bool (* is_lsyscall_fc) (GArchInstruction *);
+
+/* Identifie le numéro d'appel système en cours de manipulation. */
+typedef bool (* resolve_lsyscall_nr_fc) (tracked_path *, GArchProcessor *, const hunting_ops *, unsigned int *);
+
+/* Marque les registres associés aux n premiers arguments. */
+typedef bool (* look_for_lsyscall_args_fc) (tracked_path *, size_t, size_t);
+
+/* Commente autant que possible un appel système brut. */
+typedef void (* comment_lsyscall_fc) (tracked_path *, size_t, syscall_info_t *, comment_writer *);
+
+
+/* Opérations adaptées pour une chasse donnée */
+typedef struct _hunting_ops
+{
+    const char *arch;                       /* Rappel de l'architecture    */
+
+    is_lsyscall_fc is_syscall;              /* Identification d'un appel   */
+    resolve_lsyscall_nr_fc resolve_nr;      /* Récupération d'un numéro    */
+    look_for_lsyscall_args_fc look_for_args;/* Mise à prix de N arguments  */
+    comment_lsyscall_fc comment;            /* Inscription de commentaires */
+
+} hunting_ops;
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_HOPS_H */
diff --git a/plugins/lnxsyscalls/hops_armv7.c b/plugins/lnxsyscalls/hops_armv7.c
new file mode 100644
index 0000000..58b2702
--- /dev/null
+++ b/plugins/lnxsyscalls/hops_armv7.c
@@ -0,0 +1,262 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hops_armv7.c - recherche d'appels système spécifiques à ARMv7
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hops_armv7.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include <plugins/arm/v7/registers/basic.h>
+
+
+
+/* Détermine si l'instruction lance un appel syystème. */
+static bool is_armv7_linux_syscall(GArchInstruction *);
+
+/* Identifie le numéro d'appel système en cours de manipulation. */
+static bool resolve_armv7_linux_syscall_number(tracked_path *, GArchProcessor *, const hunting_ops *, unsigned int *);
+
+/* Marque les registres associés aux n premiers arguments. */
+static bool look_for_armv7_linux_syscall_args(tracked_path *, size_t, size_t);
+
+/* Commente autant que possible un appel système brut. */
+static void comment_armv7_linux_syscall(tracked_path *, size_t, syscall_info_t *, comment_writer *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Fournit les opérations spécifiques à ARMv7 pour une chasse.  *
+*                                                                             *
+*  Retour      : Ensemble d'opérations pour une chasse aux appels système.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const hunting_ops *get_armv7_hunting_ops(void)
+{
+    static const hunting_ops armv7_hops = {
+
+        .arch = "arm",
+
+        .is_syscall = is_armv7_linux_syscall,
+        .resolve_nr = resolve_armv7_linux_syscall_number,
+        .look_for_args = look_for_armv7_linux_syscall_args,
+        .comment = comment_armv7_linux_syscall
+
+    };
+
+    return &armv7_hops;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : instr = instruction à analyser.                              *
+*                                                                             *
+*  Description : Détermine si l'instruction lance un appel syystème.          *
+*                                                                             *
+*  Retour      : Bilan de l'analyse : true s'il s'agit bien d'un appel.       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool is_armv7_linux_syscall(GArchInstruction *instr)
+{
+    bool result;                            /* Conclusion à diffuser       */
+    const char *kwd;                        /* Désignation d'instruction   */
+
+    kwd = g_arch_instruction_get_keyword(instr, ASX_INTEL);
+
+    result = (strcmp(kwd, "svc") == 0);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : exec = suivi de l'utilisation des registres.                 *
+*                proc = processeur de l'architecture pour les instructions.   *
+*                hops = opérations spécialement adaptées à une architecture.  *
+*                nr   = numéro de l'appel système identifié. [OUT]            *
+*                                                                             *
+*  Description : Identifie le numéro d'appel système en cours de manipulation.*
+*                                                                             *
+*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool resolve_armv7_linux_syscall_number(tracked_path *exec, GArchProcessor *proc, const hunting_ops *hops, unsigned int *nr)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    GArchRegister *reg;                     /* Registre portant le numéro  */
+    bool got_nr;                            /* Bilan d'une recherche       */
+    GArchInstruction *instr;                /* Instruction d'importance    */
+    const char *kwd;                        /* Désignation d'instruction   */
+    GArchOperand *op;                       /* Opérande avec une constante */
+
+    result = false;
+
+    /* On vise r7... */
+    reg = g_armv7_basic_register_new(7);
+    mark_register_in_tracker(exec, 0, reg, NULL);
+
+    assert(count_register_tracker_stacks(exec) == 1);
+
+    got_nr = look_for_registers(exec, 0, proc, hops);
+
+    if (got_nr)
+    {
+        instr = get_register_write_location(exec, 0, reg);
+        kwd = g_arch_instruction_get_keyword(instr, ASX_INTEL);
+
+        /* ... et uniquement les instructions 'mov r7, <imm>' */
+        if (strncmp(kwd, "mov", 3) != 0)
+            goto ralsn_exit;
+
+        op = g_arch_instruction_get_operand(instr, 1);
+
+        if (!G_IS_IMM_OPERAND(op))
+            goto ralsn_exit;
+
+        *nr = g_imm_operand_get_raw_value(G_IMM_OPERAND(op));
+        result = true;
+
+    }
+
+ ralsn_exit:
+
+    g_object_unref(G_OBJECT(reg));
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : exec = chemin d'exécution à préparer.                        *
+*                sid  = identifiant de la pile d'exécution à traiter.         *
+*                argc = nombre d'arguments à repérer.                         *
+*                                                                             *
+*  Description : Marque les registres associés aux n premiers arguments.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool look_for_armv7_linux_syscall_args(tracked_path *exec, size_t sid, size_t argc)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    size_t i;                               /* Boucle de parcours          */
+    GArchRegister *reg;                     /* Registre portant le numéro  */
+
+    /**
+     * man 2 syscall :
+     *
+     *    arch/ABI   arg1   arg2   arg3   arg4   arg5   arg6   arg7
+     *    ──────────────────────────────────────────────────────────
+     *    arm/OABI   a1     a2     a3     a4     v1     v2     v3
+     *    arm/EABI   r0     r1     r2     r3     r4     r5     r6
+     */
+
+    result = (argc <= 7);
+
+    if (result)
+        for (i = 0; i < argc; i++)
+        {
+            reg = g_armv7_basic_register_new(i);
+            mark_register_in_tracker(exec, sid, reg, NULL);
+            g_object_ref(G_OBJECT(reg));
+        }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : exec   = chemin d'exécution identifié.                       *
+*                sid    = identifiant de la pile d'exécution à traiter.       *
+*                info   = fiche d'identité d'un appel système.                *
+*                writer = conservateur des commentaires à écrire au final.    *
+*                                                                             *
+*  Description : Commente autant que possible un appel système brut.          *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void comment_armv7_linux_syscall(tracked_path *exec, size_t sid, syscall_info_t *info, comment_writer *writer)
+{
+    GArchRegister *reg;                     /* Registre intervenant        */
+    GArchInstruction *instr;                /* Instruction impliquée       */
+    size_t i;                               /* Boucle de parcours          */
+
+    /* Type d'appel système */
+
+    reg = g_armv7_basic_register_new(7);
+
+    instr = get_register_write_location(exec, sid, reg);
+
+    if (instr != NULL)
+        add_comment_at(writer, info->name, instr);
+
+    g_object_unref(G_OBJECT(instr));
+
+    g_object_unref(G_OBJECT(reg));
+
+    /* Eventuels arguments */
+
+    for (i = 0; i < info->argc; i++)
+    {
+        reg = g_armv7_basic_register_new(i);
+
+        instr = get_register_write_location(exec, sid, reg);
+
+        if (instr != NULL)
+            add_comment_at(writer, info->argv[i], instr);
+
+        g_object_unref(G_OBJECT(instr));
+
+        g_object_unref(G_OBJECT(reg));
+
+    }
+
+}
diff --git a/plugins/lnxsyscalls/hops_armv7.h b/plugins/lnxsyscalls/hops_armv7.h
new file mode 100644
index 0000000..a0dad87
--- /dev/null
+++ b/plugins/lnxsyscalls/hops_armv7.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hops_armv7.h - prototypes pour la recherche d'appels système spécifiques à ARMv7
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_HOPS_ARMV7_H
+#define _PLUGINS_LNXSYSCALLS_HOPS_ARMV7_H
+
+
+#include "hops.h"
+
+
+
+/* Fournit les opérations spécifiques à ARMv7 pour une chasse. */
+const hunting_ops *get_armv7_hunting_ops(void);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_HOPS_ARMV7_H */
diff --git a/plugins/lnxsyscalls/hunter.c b/plugins/lnxsyscalls/hunter.c
new file mode 100644
index 0000000..4cac8e6
--- /dev/null
+++ b/plugins/lnxsyscalls/hunter.c
@@ -0,0 +1,346 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hunter.c - recherche de portes vers le noyau
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "hunter.h"
+
+
+#include <analysis/routine.h>
+#include <glibext/delayed-int.h>
+
+
+#include "db.h"
+
+
+
+/* Chasse à l'appel système (instance) */
+struct _GGateHunter
+{
+    GDelayedWork parent;                    /* A laisser en premier        */
+
+    const GPluginModule *plugin;            /* Liens pour les messages     */
+
+    GLoadedBinary *binary;                  /* Binaire chargé et concerné  */
+    GBinFormat *format;                     /* Format de fichier manipulé  */
+    GProcContext *context;                  /* Contexte de désassemblage   */
+
+    size_t begin;                           /* Point de départ du parcours */
+    size_t end;                             /* Point d'arrivée exclu       */
+
+    activity_id_t id;                       /* Identifiant pour messages   */
+
+    const hunting_ops *hops;                /* Opérations particulières    */
+    sqlite3 *db;                            /* Base de données à manipuler */
+
+};
+
+/* Chasse à l'appel système (classe) */
+struct _GGateHunterClass
+{
+    GDelayedWorkClass parent;               /* A laisser en premier        */
+
+};
+
+
+/* Indique le type défini pour les tâches d'étude de routines. */
+GType g_gate_hunter_get_type(void);
+
+/* Initialise la classe des tâches d'étude de routines. */
+static void g_gate_hunter_class_init(GGateHunterClass *);
+
+/* Initialise une tâche d'étude de routines. */
+static void g_gate_hunter_init(GGateHunter *);
+
+/* Supprime toutes les références externes. */
+static void g_gate_hunter_dispose(GGateHunter *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_gate_hunter_finalize(GGateHunter *);
+
+/* Effectue une recherche d'appels système. */
+static void g_gate_hunter_process(GGateHunter *, GtkStatusStack *);
+
+
+
+/* Indique le type défini pour les tâches d'étude de routines. */
+G_DEFINE_TYPE(GGateHunter, g_gate_hunter, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des tâches d'étude de routines.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_gate_hunter_class_init(GGateHunterClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GDelayedWorkClass *work;                /* Version en classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_gate_hunter_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_gate_hunter_finalize;
+
+    work = G_DELAYED_WORK_CLASS(klass);
+
+    work->run = (run_task_fc)g_gate_hunter_process;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : hunter = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une tâche d'étude de routines.                    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_gate_hunter_init(GGateHunter *hunter)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : hunter = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_gate_hunter_dispose(GGateHunter *hunter)
+{
+    g_object_unref(G_OBJECT(hunter->binary));
+
+    g_binary_format_unlock_symbols_rd(hunter->format);
+    g_object_unref(G_OBJECT(hunter->format));
+
+    g_object_unref(G_OBJECT(hunter->context));
+
+    G_OBJECT_CLASS(g_gate_hunter_parent_class)->dispose(G_OBJECT(hunter));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : hunter = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_gate_hunter_finalize(GGateHunter *hunter)
+{
+    if (hunter->db != NULL)
+        close_syscalls_database(hunter->db);
+
+    G_OBJECT_CLASS(g_gate_hunter_parent_class)->finalize(G_OBJECT(hunter));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin  = greffon à manipuler.                               *
+*                binary  = binaire dont la définition est à compléter.        *
+*                context = contexte de désassemblage.                         *
+*                begin   = point de départ du parcours de liste.              *
+*                end     = point d'arrivée exclu du parcours.                 *
+*                id      = identifiant du message affiché à l'utilisateur.    *
+*                hops    = opérations spécifiques à une architecture.         *
+*                                                                             *
+*  Description : Crée une tâche de recherche de portes différée.              *
+*                                                                             *
+*  Retour      : Tâche créée.                                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GGateHunter *g_gate_hunter_new(const GPluginModule *plugin, GLoadedBinary *binary, GProcContext *context, size_t begin, size_t end, activity_id_t id, const hunting_ops *hops)
+{
+    GGateHunter *result;                /* Tâche à retourner           */
+
+    result = g_object_new(G_TYPE_GATE_HUNTER, NULL);
+
+    result->plugin = plugin;
+
+    result->binary = binary;
+    g_object_ref(G_OBJECT(binary));
+
+    result->format = G_BIN_FORMAT(g_loaded_binary_get_format(binary));
+
+    g_binary_format_lock_symbols_rd(result->format);
+
+    result->context = context;
+    g_object_ref(G_OBJECT(context));
+
+    result->begin = begin;
+    result->end = end;
+
+    result->id = id;
+
+    result->hops = hops;
+
+    result->db = open_syscalls_database(plugin);
+    if (result->db == NULL) goto gghn_db_error;
+
+    return result;
+
+ gghn_db_error:
+
+    g_object_unref(G_OBJECT(result));
+
+    return NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : hunter = étude de routines à mener.                          *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Effectue une recherche d'appels système.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_gate_hunter_process(GGateHunter *hunter, GtkStatusStack *status)
+{
+    GArchProcessor *proc;                   /* Architecture du binaire     */
+    size_t i;                               /* Boucle de parcours #1       */
+    GBinSymbol *symbol;                     /* Commodité d'accès           */
+    const mrange_t *range;                  /* Couverture d'une routine    */
+    instr_iter_t *iter;                     /* Boucle de parcours #2       */
+    GArchInstruction *instr;                /* Instruction analysée        */
+    tracked_path *exec;                     /* Chemin d'exécution à suivre */
+    unsigned int nr;                        /* Numéro d'appel système      */
+    bool ret;                               /* Bilan d'un appel            */
+    syscall_info_t *info;                   /* Information sur l'appel     */
+    size_t loop;                            /* Quantité de boucles en vue  */
+    size_t k;                               /* Boucle de parcours #3       */
+    comment_writer *writer;                 /* Ecriture de commentaires    */
+
+    proc = g_loaded_binary_get_processor(hunter->binary);
+
+    for (i = hunter->begin; i < hunter->end; i++)
+    {
+        symbol = g_binary_format_get_symbol(hunter->format, i);
+
+        if (!G_IS_BIN_ROUTINE(symbol))
+            goto gghp_next;
+
+        range = g_binary_symbol_get_range(symbol);
+
+        iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(range));
+
+        if (iter != NULL)
+        {
+            restrict_instruction_iterator(iter, range);
+
+            for (instr = get_instruction_iterator_current(iter);
+                 instr != NULL;
+                 instr = get_instruction_iterator_next(iter))
+            {
+                if (hunter->hops->is_syscall(instr))
+                {
+                    exec = create_register_tracker(iter);
+
+                    ret = hunter->hops->resolve_nr(exec, proc, hunter->hops, &nr);
+                    if (!ret) goto unknown_syscall;
+
+                    info = extract_from_syscalls_database(hunter->db, hunter->plugin, hunter->hops->arch, nr);
+                    if (info == NULL) goto unknown_syscall;
+
+                    loop = count_register_tracker_stacks(exec);
+
+                    for (k = 0; k < loop; k++)
+                    {
+                        ret = hunter->hops->look_for_args(exec, k, info->argc);
+                        if (!ret) goto unknown_syscall;
+
+                        look_for_registers(exec, k, proc, hunter->hops);
+
+                    }
+
+                    writer = create_comment_writer();
+
+                    loop = count_register_tracker_stacks(exec);
+
+                    for (k = 0; k < loop; k++)
+                        hunter->hops->comment(exec, k, info, writer);
+
+                    write_all_comments(writer, G_PRELOAD_INFO(hunter->context));
+
+                    delete_comment_writer(writer);
+
+ unknown_syscall:
+
+                    delete_register_tracker(exec);
+
+                }
+
+                g_object_unref(G_OBJECT(instr));
+
+            }
+
+            delete_instruction_iterator(iter);
+
+        }
+
+ gghp_next:
+
+        gtk_status_stack_update_activity_value(status, hunter->id, 1);
+
+        g_object_unref(G_OBJECT(symbol));
+
+    }
+
+    g_object_unref(G_OBJECT(proc));
+
+}
diff --git a/plugins/lnxsyscalls/hunter.h b/plugins/lnxsyscalls/hunter.h
new file mode 100644
index 0000000..100f426
--- /dev/null
+++ b/plugins/lnxsyscalls/hunter.h
@@ -0,0 +1,56 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * hunter.h - prototypes pour la recherche de portes vers le noyau
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_HUNTER_H
+#define _PLUGINS_LNXSYSCALLS_HUNTER_H
+
+
+#include <analysis/binary.h>
+#include <plugins/plugin.h>
+
+
+#include "hops.h"
+
+
+
+#define G_TYPE_GATE_HUNTER               g_gate_hunter_get_type()
+#define G_GATE_HUNTER(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), g_gate_hunter_get_type(), GGateHunter))
+#define G_IS_GATE_HUNTER(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_gate_hunter_get_type()))
+#define G_GATE_HUNTER_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_GATE_HUNTER, GGateHunterClass))
+#define G_IS_GATE_HUNTER_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_GATE_HUNTER))
+#define G_GATE_HUNTER_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GATE_HUNTER, GGateHunterClass))
+
+
+/* Chasse à l'appel système (instance) */
+typedef struct _GGateHunter GGateHunter;
+
+/* Chasse à l'appel système (classe) */
+typedef struct _GGateHunterClass GGateHunterClass;
+
+
+/* Crée une tâche d'étude de routines différée. */
+GGateHunter *g_gate_hunter_new(const GPluginModule *, GLoadedBinary *, GProcContext *, size_t, size_t, activity_id_t, const hunting_ops *);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_HUNTER_H */
diff --git a/plugins/lnxsyscalls/linux-syscalls.db b/plugins/lnxsyscalls/linux-syscalls.db
new file mode 100644
index 0000000..c1ea339
Binary files /dev/null and b/plugins/lnxsyscalls/linux-syscalls.db differ
diff --git a/plugins/lnxsyscalls/syscall.c b/plugins/lnxsyscalls/syscall.c
new file mode 100644
index 0000000..e177d6e
--- /dev/null
+++ b/plugins/lnxsyscalls/syscall.c
@@ -0,0 +1,108 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * syscall.h - prototypes pour la définition d'appels système Linux
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "syscall.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : nr   = indice de l'appel système à décrire.                  *
+*                name = désignation humaine de ce même appel système.         *
+*                                                                             *
+*  Description : Crée un début de description d'appel système.                *
+*                                                                             *
+*  Retour      : Structure mise en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+syscall_info_t *create_syscall_info(unsigned int nr, const char *name)
+{
+    syscall_info_t *result;                 /* Description à retourner     */
+
+    result = (syscall_info_t *)calloc(1, sizeof(syscall_info_t));
+
+    result->nr = nr;
+    result->name = strdup(name);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info = description d'appel système à supprimer.              *
+*                                                                             *
+*  Description : Efface de la mémoire une description d'appel système.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void delete_syscall_info(syscall_info_t *info)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    free(info->name);
+
+    for (i = 0; i < info->argc; i++)
+        free(info->argv[i]);
+
+    if (info->filename != NULL)
+        free(info->filename);
+
+    free(info);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info = description d'appel système à compléter.              *
+*                arg  = description d'un argument supplémentaire.             *
+*                                                                             *
+*  Description : Ajoute un argument à une description d'appel système.        *
+*                                                                             *
+*  Retour      : Structure mise en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void append_arg_to_syscall_info(syscall_info_t *info, const char *arg)
+{
+    assert(info->argc < 6);
+
+    info->argv[info->argc++] = strdup(arg);
+
+}
diff --git a/plugins/lnxsyscalls/syscall.h b/plugins/lnxsyscalls/syscall.h
new file mode 100644
index 0000000..ecbe911
--- /dev/null
+++ b/plugins/lnxsyscalls/syscall.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * syscall.h - prototypes pour la définition d'appels système Linux
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_SYSCALL_H
+#define _PLUGINS_LNXSYSCALLS_SYSCALL_H
+
+
+#include <sys/types.h>
+
+
+
+/* Information quant à un appel */
+typedef struct _syscall_info_t
+{
+    unsigned int nr;                        /* Numéro de l'appel           */
+    char *name;                             /* Désignation de l'appel      */
+
+    size_t argc;                            /* Nombre d'arguments utilisés */
+    char *argv[6];                          /* Argument possibles          */
+
+    char *filename;                         /* Origine dans le code source */
+    unsigned int line;                      /* Numéro de ligne dans ce code*/
+
+} syscall_info_t ;
+
+
+/* Crée un début de description d'appel système. */
+syscall_info_t *create_syscall_info(unsigned int, const char *);
+
+/* Efface de la mémoire une description d'appel système. */
+void delete_syscall_info(syscall_info_t *);
+
+/* Ajoute un argument à une description d'appel système. */
+void append_arg_to_syscall_info(syscall_info_t *, const char *);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_SYSCALL_H */
diff --git a/plugins/lnxsyscalls/writer.c b/plugins/lnxsyscalls/writer.c
new file mode 100644
index 0000000..1263429
--- /dev/null
+++ b/plugins/lnxsyscalls/writer.c
@@ -0,0 +1,222 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * writer.c - mise en place de commentaires adaptés aux appels système
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "writer.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <analysis/db/items/comment.h>
+
+
+
+/* Empilement de commentaire à une adresse donnée */
+typedef struct _comment_data
+{
+    vmpa2t addr;                            /* Emplacement de l'insertion  */
+
+    char **text;                            /* Pièces de texte rapportées  */
+    size_t count;                           /* Nombre de ces pièces        */
+
+} comment_data;
+
+/* Mémorisation des commentaires à insérer */
+struct _comment_writer
+{
+    comment_data *comments;                 /* Définitions de commentaire  */
+    size_t count;                           /* Nombre de ces commentaires  */
+
+};
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Crée un espace de conservation pour commentaires d'appels.   *
+*                                                                             *
+*  Retour      : Structure de mémorisation en place.                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+comment_writer *create_comment_writer(void)
+{
+    comment_writer *result;                 /* Structure à retourner       */
+
+    result = (comment_writer *)malloc(sizeof(comment_writer));
+
+    result->comments = NULL;
+    result->count = 0;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer  = ensemble de commentaires conservés à supprimer.    *
+*                                                                             *
+*  Description : Détruit la conservation de commentaires pour appels.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void delete_comment_writer(comment_writer *writer)
+{
+    size_t i;                               /* Boucle de parcours #1       */
+    comment_data *data;                     /* Facilités d'accès           */
+    size_t k;                               /* Boucle de parcours #2       */
+
+    for (i = 0; i < writer->count; i++)
+    {
+        data = &writer->comments[i];
+
+        for (k = 0; k < data->count; k++)
+            free(data->text[k]);
+
+        if (data->text != NULL)
+            free(data->text);
+
+    }
+
+    if (writer->comments != NULL)
+        free(writer->comments);
+
+    free(writer);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer = ensemble de commentaires conservés.                 *
+*                text   = commentaire humainement lisible à insérer.          *
+*                at     = instruction dont l'adresse est la destination visée.*
+*                                                                             *
+*  Description : Complète un commentaire ou en insére un nouveau.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void add_comment_at(comment_writer *writer, const char *text, GArchInstruction *at)
+{
+    const mrange_t *range;                  /* Couverture d'une instruction*/
+    const vmpa2t *addr;                     /* Adresse de début liée       */
+    size_t i;                               /* Boucle de parcours          */
+    comment_data *target;                   /* Commentaire à éditer        */
+    bool new;                               /* Age de ce commentaire       */
+
+    range = g_arch_instruction_get_range(at);
+    addr = get_mrange_addr(range);
+
+    for (i = 0; i < writer->count; i++)
+    {
+        target = &writer->comments[i];
+
+        if (cmp_vmpa(addr, &target->addr) == 0)
+            break;
+
+    }
+
+    new = (i == writer->count);
+
+    if (new)
+    {
+        writer->comments = (comment_data *)realloc(writer->comments, ++writer->count * sizeof(comment_data));
+
+        target = &writer->comments[writer->count - 1];
+
+        copy_vmpa(&target->addr, addr);
+
+        target->text = NULL;
+        target->count = 0;
+
+    }
+
+    for (i = 0; i < target->count; i++)
+        if (strcmp(target->text[i], text) == 0)
+            break;
+
+    if (i == target->count)
+    {
+        target->text = (char **)realloc(target->text, ++target->count * sizeof(char *));
+
+        target->text[target->count - 1] = strdup(text);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : writer  = ensemble de commentaires conservés.                *
+*                preload = contexte de désassemblage avec info préchargées.   *
+*                                                                             *
+*  Description : Applique tous les commentaires à l'écriture anticipée.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void write_all_comments(comment_writer *writer, GPreloadInfo *preload)
+{
+    size_t i;                               /* Boucle de parcours #1       */
+    comment_data *target;                   /* Commentaire à éditer        */
+    GDbComment *comment;                    /* Commentaire final à intégrer*/
+    size_t k;                               /* Boucle de parcours #2       */
+
+    for (i = 0; i < writer->count; i++)
+    {
+        target = &writer->comments[i];
+
+        comment = g_db_comment_new_inlined(&target->addr, BLF_HAS_CODE, false);
+        g_db_item_set_volatile(G_DB_ITEM(comment), true);
+
+        for (k = 0; k < target->count; k++)
+        {
+            if (k > 0)
+                g_db_comment_add_static_text(comment, " / ");
+
+            g_db_comment_add_dynamic_text(comment, strdup(target->text[k]));
+
+        }
+
+        g_preload_info_add_comment(preload, comment);
+
+    }
+
+}
diff --git a/plugins/lnxsyscalls/writer.h b/plugins/lnxsyscalls/writer.h
new file mode 100644
index 0000000..113acda
--- /dev/null
+++ b/plugins/lnxsyscalls/writer.h
@@ -0,0 +1,50 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * writer.h - prototypes pour la mise en place de commentaires adaptés aux appels système
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide 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.
+ *
+ *  Chrysalide 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_LNXSYSCALLS_WRITER_H
+#define _PLUGINS_LNXSYSCALLS_WRITER_H
+
+
+#include <format/preload.h>
+
+
+
+/* Mémorisation des commentaires à insérer */
+typedef struct _comment_writer comment_writer;
+
+
+/* Crée un espace de conservation pour commentaires d'appels. */
+comment_writer *create_comment_writer(void);
+
+/* Détruit la conservation de commentaires pour appels. */
+void delete_comment_writer(comment_writer *);
+
+/* Complète un commentaire ou en insére un nouveau. */
+void add_comment_at(comment_writer *, const char *, GArchInstruction *);
+
+/* Applique tous les commentaires à l'écriture anticipée. */
+void write_all_comments(comment_writer *, GPreloadInfo *);
+
+
+
+#endif  /* _PLUGINS_LNXSYSCALLS_WRITER_H */
diff --git a/src/arch/instriter.c b/src/arch/instriter.c
index db322a2..d968ba8 100644
--- a/src/arch/instriter.c
+++ b/src/arch/instriter.c
@@ -81,6 +81,41 @@ instr_iter_t *create_instruction_iterator(GArchProcessor *proc, size_t index)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : iter = itérateur à copie.                                    *
+*                                                                             *
+*  Description : Duplique un itérateur de parcours d'instructions existant.   *
+*                                                                             *
+*  Retour      : Itérateur prêt à emploi.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+instr_iter_t *copy_instruction_iterator(const instr_iter_t *iter)
+{
+    instr_iter_t *result;                   /* Structure à retourner       */
+
+    result = (instr_iter_t *)malloc(sizeof(instr_iter_t));
+
+    g_object_ref(G_OBJECT(iter->proc));
+
+    result->proc = iter->proc;
+    result->stamp = iter->stamp;
+
+    result->index = iter->index;
+
+    result->is_restricted = iter->is_restricted;
+
+    if (result->is_restricted)
+        copy_mrange(&result->restriction, &iter->restriction);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : iter = itérateur à traiter.                                  *
 *                                                                             *
 *  Description : Détruit un itérateur mis en place.                           *
diff --git a/src/arch/instriter.h b/src/arch/instriter.h
index 1a0003f..68db9cb 100644
--- a/src/arch/instriter.h
+++ b/src/arch/instriter.h
@@ -39,6 +39,9 @@ typedef struct _instr_iter_t instr_iter_t;
 /* Construit un itérateur pour parcourir des instructions. */
 instr_iter_t *create_instruction_iterator(GArchProcessor *, size_t);
 
+/* Duplique un itérateur de parcours d'instructions existant. */
+instr_iter_t *copy_instruction_iterator(const instr_iter_t *);
+
 /* Détruit un itérateur mis en place. */
 void delete_instruction_iterator(instr_iter_t *);
 
diff --git a/src/core/paths.c b/src/core/paths.c
index 13b9cbe..8e825d2 100644
--- a/src/core/paths.c
+++ b/src/core/paths.c
@@ -136,8 +136,8 @@ char *find_plugin_file(const char *pgname, const char *filename)
 
 #ifndef DISCARD_LOCAL
 
-    asprintf(&dirname, "%s%splugins%s%s%s%s",
-             PACKAGE_SOURCE_DIR, G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S, pgname, G_DIR_SEPARATOR_S, filename);
+    asprintf(&dirname, "%s%splugins%s%s",
+             PACKAGE_SOURCE_DIR, G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S, pgname);
 
     result = find_file_in_directory(dirname, filename);
 
-- 
cgit v0.11.2-87-g4458