From e26ba6f0429e079785bfc96e0ea55c814537e76f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 29 Feb 2020 10:40:35 +0100
Subject: Broken ARMv7 basic blocks depending on conditional flags.

---
 plugins/arm/v7/link.c                 | 19 ++++++++++++++++---
 plugins/pychrysalide/arch/constants.c |  1 +
 src/arch/instruction.h                | 17 +++++++++--------
 3 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/plugins/arm/v7/link.c b/plugins/arm/v7/link.c
index 263bb49..30b91f9 100644
--- a/plugins/arm/v7/link.c
+++ b/plugins/arm/v7/link.c
@@ -29,6 +29,7 @@
 
 
 #include "operands/reglist.h"
+#include "../instruction.h"
 #include "../register.h"
 
 
@@ -50,16 +51,22 @@
 
 void handle_armv7_conditional_branch_from_register(GArchInstruction *instr, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
 {
+    ArmCondCode cond;                       /* Condition d'exécution       */
+    ArchInstrFlag flag;                     /* Fanion particulier appliqué */
     GArchOperand *op;                       /* Opérande numérique en place */
     GArmRegister *reg;                      /* Registre matériel manipulé  */
 
+    cond = g_arm_instruction_get_cond(G_ARM_INSTRUCTION(instr));
+
+    flag = (cond == ACC_AL ? AIF_RETURN_POINT : AIF_COND_RETURN_POINT);
+
     op = g_arch_instruction_get_operand(instr, 0);
     assert(G_IS_REGISTER_OPERAND(op));
 
     reg = G_ARM_REGISTER(g_register_operand_get_register(G_REGISTER_OPERAND(op)));
 
     if (g_arm_register_get_index(reg) == 14 /* lr */)
-        g_arch_instruction_set_flag(instr, AIF_RETURN_POINT);
+        g_arch_instruction_set_flag(instr, flag);
 
     else
     {
@@ -70,7 +77,7 @@ void handle_armv7_conditional_branch_from_register(GArchInstruction *instr, GArc
          * vers l'instruction suivante, donc on marque le branchement comme
          * étant un point de retour.
          */
-        g_arch_instruction_set_flag(instr, AIF_RETURN_POINT);
+        g_arch_instruction_set_flag(instr, flag);
 
     }
 
@@ -98,12 +105,18 @@ void handle_armv7_conditional_branch_from_register(GArchInstruction *instr, GArc
 
 void handle_armv7_return_from_pop(GArchInstruction *instr, GArchProcessor *proc, GProcContext *context, GExeFormat *format)
 {
+    ArmCondCode cond;                       /* Condition d'exécution       */
+    ArchInstrFlag flag;                     /* Fanion particulier appliqué */
     GArchOperand *op;                       /* Opérande numérique en place */
     GArmV7RegListOperand *reglist;          /* Autre version de l'instance */
     size_t count;                           /* Nombre de registres présents*/
     size_t i;                               /* Boucle de parcours          */
     GArmRegister *reg;                      /* Registre matériel manipulé  */
 
+    cond = g_arm_instruction_get_cond(G_ARM_INSTRUCTION(instr));
+
+    flag = (cond == ACC_AL ? AIF_RETURN_POINT : AIF_COND_RETURN_POINT);
+
     op = g_arch_instruction_get_operand(instr, 0);
     assert(G_IS_ARMV7_REGLIST_OPERAND(op));
 
@@ -116,7 +129,7 @@ void handle_armv7_return_from_pop(GArchInstruction *instr, GArchProcessor *proc,
         reg = G_ARM_REGISTER(g_armv7_reglist_operand_get_register(reglist, i));
 
         if (g_arm_register_get_index(reg) == 15 /* pc */)
-            g_arch_instruction_set_flag(instr, AIF_RETURN_POINT);
+            g_arch_instruction_set_flag(instr, flag);
 
         g_object_unref(G_OBJECT(reg));
 
diff --git a/plugins/pychrysalide/arch/constants.c b/plugins/pychrysalide/arch/constants.c
index 5e9ad37..b7dd8a1 100644
--- a/plugins/pychrysalide/arch/constants.c
+++ b/plugins/pychrysalide/arch/constants.c
@@ -55,6 +55,7 @@ bool define_arch_instruction_constants(PyTypeObject *type)
     result = add_const_to_group(values, "NONE", AIF_NONE);
     if (result) result = add_const_to_group(values, "ROUTINE_START", AIF_ROUTINE_START);
     if (result) result = add_const_to_group(values, "RETURN_POINT", AIF_RETURN_POINT);
+    if (result) result = add_const_to_group(values, "COND_RETURN_POINT", AIF_COND_RETURN_POINT);
     if (result) result = add_const_to_group(values, "CALL", AIF_CALL);
     if (result) result = add_const_to_group(values, "LOW_USER", AIF_LOW_USER);
     if (result) result = add_const_to_group(values, "HIGH_USER", AIF_HIGH_USER);
diff --git a/src/arch/instruction.h b/src/arch/instruction.h
index d0d05e6..e8ba4bd 100644
--- a/src/arch/instruction.h
+++ b/src/arch/instruction.h
@@ -55,17 +55,18 @@ typedef struct _GArchInstructionClass GArchInstructionClass;
 
 /* Drapeaux pour informations complémentaires */
 
-#define AIF_USER_BIT 3
+#define AIF_USER_BIT 4
 
 typedef enum _ArchInstrFlag
 {
-    AIF_NONE            = (0 << 0),         /* Aucune information          */
-    AIF_ROUTINE_START   = (1 << 0),         /* Début de routine            */
-    AIF_RETURN_POINT    = (1 << 1),         /* Retour de fonction appelée  */
-    AIF_CALL            = (1 << 2),         /* Instruction d'appel         */
-
-    AIF_LOW_USER        = (1 << AIF_USER_BIT), /* Premier bit disponible   */
-    AIF_HIGH_USER       = (1 << 14),        /* Dernier bit disponible      */
+    AIF_NONE              = (0 << 0),       /* Aucune information          */
+    AIF_ROUTINE_START     = (1 << 0),       /* Début de routine            */
+    AIF_RETURN_POINT      = (1 << 1),       /* Retour de fonction appelée  */
+    AIF_COND_RETURN_POINT = (1 << 2),       /* Retour éventuel de fonction */
+    AIF_CALL              = (1 << 3),       /* Instruction d'appel         */
+
+    AIF_LOW_USER          = (1 << AIF_USER_BIT), /* Premier bit disponible */
+    AIF_HIGH_USER         = (1 << 14),      /* Dernier bit disponible      */
 
 } ArchInstrFlag;
 
-- 
cgit v0.11.2-87-g4458