From a4fde950b940582a0e21a84c6c98a79f945fde02 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 14 Jan 2019 08:43:32 +0100
Subject: Detected self loops in basic blocks.

---
 src/analysis/disass/loop.c       | 10 ++++++-
 tests/analysis/disass/Makefile   |  5 +++-
 tests/analysis/disass/block.py   | 37 +++++++++++++++++++++++
 tests/analysis/disass/selfloop.c | 64 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 114 insertions(+), 2 deletions(-)
 create mode 100755 tests/analysis/disass/selfloop.c

diff --git a/src/analysis/disass/loop.c b/src/analysis/disass/loop.c
index 9e964e5..b82d58e 100644
--- a/src/analysis/disass/loop.c
+++ b/src/analysis/disass/loop.c
@@ -408,7 +408,15 @@ static void define_basic_blocks_loops(GBlockList *list, bblock_info_t *info)
             links = get_block_successors(block, info, &count);
 
             for (k = 0; k < count; k++)
-                if (links[k].info == iter->iloop_header)
+                if (links[k].info == iter->iloop_header
+                    /**
+                     * Il se peut qu'un bloc fasse référence à lui même !
+                     *
+                     * Cf. tests/analysis/disass/selfloop.c
+                     *
+                     * On évite ici une boucle sans fin en officialisant cette boucle.
+                     */
+                    || links[k].info == iter)
                 {
                     g_basic_block_get_boundaries(G_BASIC_BLOCK(block), NULL, &last);
                     g_basic_block_get_boundaries(G_BASIC_BLOCK(links[k].linked), &first, NULL);
diff --git a/tests/analysis/disass/Makefile b/tests/analysis/disass/Makefile
index 030e868..ef70dec 100644
--- a/tests/analysis/disass/Makefile
+++ b/tests/analysis/disass/Makefile
@@ -1,5 +1,5 @@
 
-EXECUTABLES=hello endofname irreducible
+EXECUTABLES=hello endofname irreducible selfloop
 
 all: $(EXECUTABLES)
 
@@ -12,5 +12,8 @@ endofname: endofname.c
 irreducible: irreducible.c
 	$(ARM_CROSS)gcc $< -o $@
 
+selfloop: selfloop.c
+	$(ARM_CROSS)gcc $< -o $@
+
 clean:
 	rm -f $(EXECUTABLES)
diff --git a/tests/analysis/disass/block.py b/tests/analysis/disass/block.py
index 84fa4c3..10a2c80 100644
--- a/tests/analysis/disass/block.py
+++ b/tests/analysis/disass/block.py
@@ -31,6 +31,8 @@ class TestBasicBlocks(ChrysalideTestCase):
 
         os.system('make -C %s irreducible > /dev/null 2>&1' % dirpath)
 
+        os.system('make -C %s selfloop > /dev/null 2>&1' % dirpath)
+
 
     @classmethod
     def tearDownClass(cls):
@@ -110,3 +112,38 @@ class TestBasicBlocks(ChrysalideTestCase):
                     loop_count += 1
 
         self.assertEqual(loop_count, 2)
+
+
+    def testSelfLoopBlock(self):
+        """Validate support for self loop blocks."""
+
+        fullname = sys.modules[self.__class__.__module__].__file__
+        filename = os.path.basename(fullname)
+
+        baselen = len(fullname) - len(filename)
+
+        cnt = FileContent(fullname[:baselen] + 'selfloop')
+        self.assertIsNotNone(cnt)
+
+        fmt = ElfFormat(cnt)
+        self.assertIsNotNone(fmt)
+
+        binary = LoadedBinary(fmt)
+        self.assertIsNotNone(binary)
+
+        binary.analyze_and_wait()
+
+        sym = fmt.find_symbol_by_label('string_array_len')
+        self.assertIsNotNone(sym)
+
+        found = sym.basic_blocks.find_by_starting_addr(sym.range.addr)
+        self.assertIsNotNone(found)
+
+        loop_count = 0
+
+        for blk in sym.basic_blocks:
+            for _, dt in blk.destinations:
+                if dt == ArchInstruction.ILT_LOOP:
+                    loop_count += 1
+
+        self.assertEqual(loop_count, 1)
diff --git a/tests/analysis/disass/selfloop.c b/tests/analysis/disass/selfloop.c
new file mode 100755
index 0000000..fe9cf21
--- /dev/null
+++ b/tests/analysis/disass/selfloop.c
@@ -0,0 +1,64 @@
+
+#include <stdio.h>
+
+
+/**
+ * On reproduit un code similaire à celui d'un fichier de Busybox (busybox-1.30.0/libbb/appletlib.c).
+ *
+ * La commande de compilation est :
+ *
+ * arm-linux-gnueabi-gcc -Wp,-MD,libbb/.appletlib.o.d   -std=gnu99 -Iinclude -Ilibbb  -include include/autoconf.h -D_GNU_SOURCE -DNDEBUG  -D"BB_VER=KBUILD_STR(1.30.0)"  -Wall -Wshadow -Wwrite-strings -Wundef -Wstrict-prototypes -Wunused -Wunused-parameter -Wunused-function -Wunused-value -Wmissing-prototypes -Wmissing-declarations -Wno-format-security -Wdeclaration-after-statement -Wold-style-definition -fno-builtin-strlen -finline-limit=0 -fomit-frame-pointer -ffunction-sections -fdata-sections -fno-guess-branch-probability -funsigned-char -static-libgcc -falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1 -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-builtin-printf -Os     -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(appletlib)"  -D"KBUILD_MODNAME=KBUILD_STR(appletlib)" -c -o libbb/appletlib.o libbb/appletlib.c
+ *
+ */
+
+
+/*
+unsigned FAST_FUNC string_array_len(char **argv)
+{
+	char **start = argv;
+
+	while (*argv)
+		argv++;
+
+	return argv - start;
+}
+*/
+
+unsigned __attribute__ ((naked)) string_array_len(char **argv)
+{
+    /*
+   0x00009a0c <+0>:	mov	r2, r0
+   0x00009a10 <+4>:	mov	r3, r2
+   0x00009a14 <+8>:	ldr	r1, [r3]
+   0x00009a18 <+12>:	add	r2, r2, #4
+   0x00009a1c <+16>:	cmp	r1, #0
+   0x00009a20 <+20>:	bne	0x9a10 <string_array_len+4>
+   0x00009a24 <+24>:	rsb	r0, r0, r3
+   0x00009a28 <+28>:	asr	r0, r0, #2
+   0x00009a2c <+32>:	bx	lr
+    */
+
+asm (
+
+     "mov	r2, r0"             "\n"
+
+     ".Lbl_9a10%=:"             "\n"
+
+     "mov	r3, r2"             "\n"
+     "ldr	r1, [r3]"           "\n"
+     "add	r2, r2, #4"         "\n"
+     "cmp	r1, #0"             "\n"
+     "bne   .Lbl_9a10%="        "\n"
+     "rsb	r0, r0, r3"         "\n"
+     "asr	r0, r0, #2"         "\n"
+     "bx	lr"                 "\n"
+
+     ::"r" (argv));
+
+}
+
+int main(int argc, char **argv)
+{
+    return string_array_len(argv);
+
+}
-- 
cgit v0.11.2-87-g4458