Having DF escape is BAD(tm).

Linus; you suggested this one, but since DF really is only used from
ASM and the failure case is fairly obvious, do we really need this?
OTOH the patch is fairly small and simple.

Suggested-by: Linus Torvalds <torva...@linux-foundation.org>
Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org>
---
 tools/objtool/arch.h            |    4 +++-
 tools/objtool/arch/x86/decode.c |    8 ++++++++
 tools/objtool/check.c           |   25 +++++++++++++++++++++++++
 tools/objtool/check.h           |    2 +-
 4 files changed, 37 insertions(+), 2 deletions(-)

--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -35,7 +35,9 @@
 #define INSN_NOP               10
 #define INSN_STAC              11
 #define INSN_CLAC              12
-#define INSN_OTHER             13
+#define INSN_STD               13
+#define INSN_CLD               14
+#define INSN_OTHER             15
 #define INSN_LAST              INSN_OTHER
 
 enum op_dest_type {
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -451,6 +451,14 @@ int arch_decode_instruction(struct elf *
                *type = INSN_CALL;
                break;
 
+       case 0xfc:
+               *type = INSN_CLD;
+               break;
+
+       case 0xfd:
+               *type = INSN_STD;
+               break;
+
        case 0xff:
                if (modrm_reg == 2 || modrm_reg == 3)
 
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1903,6 +1903,12 @@ static int validate_call(struct instruct
                return 1;
        }
 
+       if (state->df) {
+               WARN_FUNC("call to %s() with DF set",
+                               insn->sec, insn->offset, insn_dest_name(insn));
+               return 1;
+       }
+
        return 0;
 }
 
@@ -2044,6 +2050,11 @@ static int validate_branch(struct objtoo
                                return 1;
                        }
 
+                       if (state.df) {
+                               WARN_FUNC("return with DF set", sec, 
insn->offset);
+                               return 1;
+                       }
+
                        if (func && has_modified_stack_frame(&state)) {
                                WARN_FUNC("return with modified stack frame",
                                          sec, insn->offset);
@@ -2172,6 +2183,20 @@ static int validate_branch(struct objtoo
                        state.uaccess = false;
                        break;
 
+               case INSN_STD:
+                       if (state.df)
+                               WARN_FUNC("recursive STD", sec, insn->offset);
+
+                       state.df = true;
+                       break;
+
+               case INSN_CLD:
+                       if (!state.df && insn->func)
+                               WARN_FUNC("redundant CLD", sec, insn->offset);
+
+                       state.df = false;
+                       break;
+
                default:
                        break;
                }
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -31,7 +31,7 @@ struct insn_state {
        int stack_size;
        unsigned char type;
        bool bp_scratch;
-       bool drap, end, uaccess;
+       bool drap, end, uaccess, df;
        unsigned int uaccess_stack;
        int drap_reg, drap_offset;
        struct cfi_reg vals[CFI_NUM_REGS];


Reply via email to