linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Peter Zijlstra <peterz@infradead.org>
To: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: tglx@linutronix.de, linux-kernel@vger.kernel.org, x86@kernel.org,
	mhiramat@kernel.org, mbenes@suse.cz
Subject: Re: [PATCH v4 01/13] objtool: Remove CFI save/restore special case
Date: Thu, 26 Mar 2020 20:57:18 +0100	[thread overview]
Message-ID: <20200326195718.GD2452@worktop.programming.kicks-ass.net> (raw)
In-Reply-To: <20200326154938.GO20713@hirez.programming.kicks-ass.net>

On Thu, Mar 26, 2020 at 04:49:38PM +0100, Peter Zijlstra wrote:
> > The 'insn == first' check isn't ideal, but at least it works (I think?).
> 
> It works, yes, for exactly this one case.

How's this? Ignore the ignore_cfi bits, that's a 'failed' experiment.

---
 arch/x86/include/asm/orc_types.h       |   2 +
 arch/x86/include/asm/processor.h       |   6 +-
 arch/x86/include/asm/unwind_hints.h    |   4 ++
 tools/arch/x86/include/asm/orc_types.h |   2 +
 tools/objtool/check.c                  | 109 +++++++++++++++++++--------------
 tools/objtool/check.h                  |   3 +-
 6 files changed, 75 insertions(+), 51 deletions(-)

diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h
index 6e060907c163..82b5c685341a 100644
--- a/arch/x86/include/asm/orc_types.h
+++ b/arch/x86/include/asm/orc_types.h
@@ -60,6 +60,8 @@
 #define ORC_TYPE_REGS_IRET		2
 #define UNWIND_HINT_TYPE_SAVE		3
 #define UNWIND_HINT_TYPE_RESTORE	4
+#define UNWIND_HINT_TYPE_IGNORE		5
+#define UNWIND_HINT_TYPE_IRET_CONT	6

 #ifndef __ASSEMBLY__
 /*
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 94789db550df..45c74cbc0a83 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -728,8 +728,8 @@ static inline void sync_core(void)
 	unsigned int tmp;

 	asm volatile (
-		UNWIND_HINT_SAVE
 		"mov %%ss, %0\n\t"
+		UNWIND_HINT_SAVE
 		"pushq %q0\n\t"
 		"pushq %%rsp\n\t"
 		"addq $8, (%%rsp)\n\t"
@@ -737,9 +737,9 @@ static inline void sync_core(void)
 		"mov %%cs, %0\n\t"
 		"pushq %q0\n\t"
 		"pushq $1f\n\t"
+		UNWIND_HINT_IRET_CONT
 		"iretq\n\t"
-		UNWIND_HINT_RESTORE
-		"1:"
+		"1:\n\t"
 		: "=&r" (tmp), ASM_CALL_CONSTRAINT : : "cc", "memory");
 #endif
 }
diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h
index f5e2eb12cb71..d8a07749c323 100644
--- a/arch/x86/include/asm/unwind_hints.h
+++ b/arch/x86/include/asm/unwind_hints.h
@@ -112,6 +112,10 @@

 #define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE, 0)

+#define UNWIND_HINT_IGNORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_IGNORE, 0)
+
+#define UNWIND_HINT_IRET_CONT UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_IRET_CONT, 0)
+
 #endif /* __ASSEMBLY__ */

 #endif /* _ASM_X86_UNWIND_HINTS_H */
diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h
index 6e060907c163..82b5c685341a 100644
--- a/tools/arch/x86/include/asm/orc_types.h
+++ b/tools/arch/x86/include/asm/orc_types.h
@@ -60,6 +60,8 @@
 #define ORC_TYPE_REGS_IRET		2
 #define UNWIND_HINT_TYPE_SAVE		3
 #define UNWIND_HINT_TYPE_RESTORE	4
+#define UNWIND_HINT_TYPE_IGNORE		5
+#define UNWIND_HINT_TYPE_IRET_CONT	6

 #ifndef __ASSEMBLY__
 /*
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e637a4a38d2a..03bac6cb313c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1259,14 +1259,25 @@ static int read_unwind_hints(struct objtool_file *file)

 		cfa = &insn->state.cfa;

-		if (hint->type == UNWIND_HINT_TYPE_SAVE) {
+		switch (hint->type) {
+		case UNWIND_HINT_TYPE_SAVE:
 			insn->save = true;
 			continue;

-		} else if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
+		case UNWIND_HINT_TYPE_RESTORE:
 			insn->restore = true;
-			insn->hint = true;
 			continue;
+
+		case UNWIND_HINT_TYPE_IGNORE:
+			insn->ignore_cfi = true;
+			continue;
+
+		case UNWIND_HINT_TYPE_IRET_CONT:
+			insn->iret_cont = true;
+			continue;
+
+		default:
+			break;
 		}

 		insn->hint = true;
@@ -1558,6 +1569,9 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
 	struct cfi_reg *cfa = &state->cfa;
 	struct cfi_reg *regs = state->regs;

+	if (insn->ignore_cfi)
+		return 0;
+
 	/* stack operations don't make sense with an undefined CFA */
 	if (cfa->base == CFI_UNDEFINED) {
 		if (insn->func) {
@@ -1993,6 +2007,37 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
 	return validate_call(insn, state);
 }

+static int insn_hint_restore(struct objtool_file *file, struct section *sec,
+			     struct symbol *func, struct instruction *insn,
+			     struct insn_state *state)
+{
+	struct instruction *save_insn, *i;
+
+	i = insn;
+	save_insn = NULL;
+	func_for_each_insn_continue_reverse(file, func, i) {
+		if (i->save) {
+			save_insn = i;
+			break;
+		}
+	}
+
+	if (!save_insn) {
+		WARN_FUNC("no corresponding CFI save for CFI restore",
+			  sec, insn->offset);
+		return 1;
+	}
+
+	if (!save_insn->visited) {
+		WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
+			  sec, insn->offset);
+		return 1;
+	}
+
+	*state = save_insn->state;
+	return 0;
+}
+
 /*
  * Follow the branch starting at the given instruction, and recursively follow
  * any other branches (jumps).  Meanwhile, track the frame pointer state at
@@ -2000,15 +2045,14 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
  * tools/objtool/Documentation/stack-validation.txt.
  */
 static int validate_branch(struct objtool_file *file, struct symbol *func,
-			   struct instruction *first, struct insn_state state)
+			   struct instruction *insn, struct insn_state state)
 {
+	struct instruction *next_insn;
 	struct alternative *alt;
-	struct instruction *insn, *next_insn;
 	struct section *sec;
 	u8 visited;
 	int ret;

-	insn = first;
 	sec = insn->sec;

 	if (insn->alt_group && list_empty(&insn->alts)) {
@@ -2034,7 +2078,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,

 		visited = 1 << state.uaccess;
 		if (insn->visited) {
-			if (!insn->hint && !insn_state_match(insn, &state))
+			if ((!insn->hint && !insn->restore) && !insn_state_match(insn, &state))
 				return 1;

 			if (insn->visited & visited)
@@ -2042,47 +2086,12 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 		}

 		if (insn->hint) {
-			if (insn->restore) {
-				struct instruction *save_insn, *i;
-
-				i = insn;
-				save_insn = NULL;
-				func_for_each_insn_continue_reverse(file, func, i) {
-					if (i->save) {
-						save_insn = i;
-						break;
-					}
-				}
-
-				if (!save_insn) {
-					WARN_FUNC("no corresponding CFI save for CFI restore",
-						  sec, insn->offset);
-					return 1;
-				}
-
-				if (!save_insn->visited) {
-					/*
-					 * Oops, no state to copy yet.
-					 * Hopefully we can reach this
-					 * instruction from another branch
-					 * after the save insn has been
-					 * visited.
-					 */
-					if (insn == first)
-						return 0;
-
-					WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
-						  sec, insn->offset);
-					return 1;
-				}
-
-				insn->state = save_insn->state;
-			}
-
 			state = insn->state;
-
-		} else
+		} else {
+			if (insn->restore)
+				insn_hint_restore(file, sec, func, insn, &state);
 			insn->state = state;
+		}

 		insn->visited |= visited;

@@ -2191,11 +2200,17 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 			break;

 		case INSN_CONTEXT_SWITCH:
-			if (func && (!next_insn || !next_insn->hint)) {
+			if (insn->iret_cont) {
+				insn_hint_restore(file, sec, func, insn, &state);
+				break;
+			}
+
+			if (func) {
 				WARN_FUNC("unsupported instruction in callable function",
 					  sec, insn->offset);
 				return 1;
 			}
+
 			return 0;

 		case INSN_STACK:
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 6d875ca6fce0..f2b6172e119b 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -33,7 +33,8 @@ struct instruction {
 	unsigned int len;
 	enum insn_type type;
 	unsigned long immediate;
-	bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts;
+	bool alt_group, dead_end, ignore, ignore_alts;
+	bool hint, save, restore, ignore_cfi, iret_cont;
 	bool retpoline_safe;
 	u8 visited;
 	struct symbol *call_dest;


  reply	other threads:[~2020-03-26 19:57 UTC|newest]

Thread overview: 63+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-25 17:45 [PATCH v4 00/13] objtool: vmlinux.o and moinstr validation Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 01/13] objtool: Remove CFI save/restore special case Peter Zijlstra
2020-03-26 11:30   ` Peter Zijlstra
2020-03-26 12:58     ` Peter Zijlstra
2020-03-26 13:44       ` Josh Poimboeuf
2020-03-26 15:38         ` Peter Zijlstra
2020-03-27  4:19           ` Josh Poimboeuf
2020-03-26 14:44       ` Miroslav Benes
2020-03-26 15:04         ` Miroslav Benes
2020-03-26 13:00     ` Peter Zijlstra
2020-03-26 13:56     ` Josh Poimboeuf
2020-03-26 15:49       ` Peter Zijlstra
2020-03-26 19:57         ` Peter Zijlstra [this message]
2020-03-27  1:00           ` Josh Poimboeuf
2020-03-30 17:02             ` Peter Zijlstra
2020-03-30 19:02               ` Josh Poimboeuf
2020-03-30 20:02                 ` Peter Zijlstra
2020-03-30 20:29                   ` Peter Zijlstra
2020-03-31 11:16                   ` [RFC][PATCH] objtool,ftrace: Implement UNWIND_HINT_RET_OFFSET Peter Zijlstra
2020-03-31 15:31                     ` Steven Rostedt
2020-03-31 16:06                       ` [RFC][PATCH] x86,ftrace: Shrink ftrace_regs_caller() by one byte Peter Zijlstra
2020-03-31 19:58                       ` [RFC][PATCH] objtool,ftrace: Implement UNWIND_HINT_RET_OFFSET Peter Zijlstra
2020-03-31 20:26                         ` Josh Poimboeuf
2020-03-31 20:23                     ` Josh Poimboeuf
2020-03-31 20:40                       ` Peter Zijlstra
2020-03-31 21:07                         ` Peter Zijlstra
2020-03-31 21:17                         ` Josh Poimboeuf
2020-03-31 21:20                           ` Josh Poimboeuf
2020-03-31 22:27                             ` [PATCH v2] " Peter Zijlstra
2020-04-01 14:14                               ` Josh Poimboeuf
2020-04-01 14:22                                 ` Peter Zijlstra
2020-04-01 14:39                                   ` Josh Poimboeuf
2020-04-01 15:38                                     ` Peter Zijlstra
2020-04-01 15:39                                     ` Steven Rostedt
2020-04-01 15:43                               ` Julien Thierry
2020-04-01 17:09                                 ` Peter Zijlstra
2020-04-01 17:33                                   ` Steven Rostedt
2020-04-01 17:45                                     ` Peter Zijlstra
2020-04-01 18:20                                       ` Steven Rostedt
2020-04-01 20:20                                         ` Peter Zijlstra
2020-04-01 17:37                                   ` Josh Poimboeuf
2020-04-02  6:41                                   ` Julien Thierry
2020-04-02  6:56                                     ` Julien Thierry
2020-04-02  7:50                                     ` Peter Zijlstra
2020-04-02  8:16                                       ` Julien Thierry
2020-04-02  8:17                                       ` Peter Zijlstra
2020-04-02  8:29                                         ` Julien Thierry
2020-04-02  8:58                                           ` Miroslav Benes
2020-03-25 17:45 ` [PATCH v4 02/13] objtool: Factor out CFI hints Peter Zijlstra
2020-03-25 18:26   ` Miroslav Benes
2020-03-25 19:41     ` Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 03/13] objtool: Rename struct cfi_state Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 04/13] objtool: Fix !CFI insn_state propagation Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 05/13] objtool: Implement noinstr validation Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 06/13] objtool: Optimize !vmlinux.o again Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 07/13] objtool: Use sec_offset_hash() for insn_hash Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 08/13] objtool: Detect loading function pointers across noinstr Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 09/13] kbuild/objtool: Add objtool-vmlinux.o pass Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 10/13] objtool: Avoid iterating !text section symbols Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 11/13] objtool: Rearrange validate_section() Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 12/13] objtool: Add STT_NOTYPE noinstr validation Peter Zijlstra
2020-03-25 17:45 ` [PATCH v4 13/13] objtool: Also consider .entry.text as noinstr Peter Zijlstra
2020-03-25 19:03 ` [PATCH v4 00/13] objtool: vmlinux.o and moinstr validation Miroslav Benes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200326195718.GD2452@worktop.programming.kicks-ass.net \
    --to=peterz@infradead.org \
    --cc=jpoimboe@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=mhiramat@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).