Commit fe1042b1 authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Ingo Molnar
Browse files

objtool: Split INSN_CONTEXT_SWITCH into INSN_SYSCALL and INSN_SYSRET



INSN_CONTEXT_SWITCH is ambiguous.  It can represent both call semantics
(SYSCALL, SYSENTER) and return semantics (SYSRET, IRET, RETS, RETU).
Those differ significantly: calls preserve control flow whereas returns
terminate it.

Objtool uses an arbitrary rule for INSN_CONTEXT_SWITCH that almost works
by accident: if in a function, keep going; otherwise stop.  It should
instead be based on the semantics of the underlying instruction.

In preparation for improving that, split INSN_CONTEXT_SWITCH into
INSN_SYCALL and INSN_SYSRET.

No functional change.

Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/19a76c74d2c051d3bc9a775823cafc65ad267a7a.1744095216.git.jpoimboe@kernel.org
parent a8df7d0e
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -522,7 +522,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
			case INAT_PFX_REPNE:
				if (modrm == 0xca)
					/* eretu/erets */
					insn->type = INSN_CONTEXT_SWITCH;
					insn->type = INSN_SYSRET;
				break;
			default:
				if (modrm == 0xca)
@@ -535,11 +535,15 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec

			insn->type = INSN_JUMP_CONDITIONAL;

		} else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
			   op2 == 0x35) {
		} else if (op2 == 0x05 || op2 == 0x34) {

			/* sysenter, sysret */
			insn->type = INSN_CONTEXT_SWITCH;
			/* syscall, sysenter */
			insn->type = INSN_SYSCALL;

		} else if (op2 == 0x07 || op2 == 0x35) {

			/* sysret, sysexit */
			insn->type = INSN_SYSRET;

		} else if (op2 == 0x0b || op2 == 0xb9) {

@@ -676,7 +680,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec

	case 0xca: /* retf */
	case 0xcb: /* retf */
		insn->type = INSN_CONTEXT_SWITCH;
		insn->type = INSN_SYSRET;
		break;

	case 0xe0: /* loopne */
@@ -721,7 +725,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
		} else if (modrm_reg == 5) {

			/* jmpf */
			insn->type = INSN_CONTEXT_SWITCH;
			insn->type = INSN_SYSRET;

		} else if (modrm_reg == 6) {

+4 −2
Original line number Diff line number Diff line
@@ -3684,7 +3684,8 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,

			break;

		case INSN_CONTEXT_SWITCH:
		case INSN_SYSCALL:
		case INSN_SYSRET:
			if (func) {
				if (!next_insn || !next_insn->hint) {
					WARN_INSN(insn, "unsupported instruction in callable function");
@@ -3886,7 +3887,8 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn)
			WARN_INSN(insn, "RET before UNTRAIN");
			return 1;

		case INSN_CONTEXT_SWITCH:
		case INSN_SYSCALL:
		case INSN_SYSRET:
			if (insn_func(insn))
				break;
			return 0;
+2 −1
Original line number Diff line number Diff line
@@ -19,7 +19,8 @@ enum insn_type {
	INSN_CALL,
	INSN_CALL_DYNAMIC,
	INSN_RETURN,
	INSN_CONTEXT_SWITCH,
	INSN_SYSCALL,
	INSN_SYSRET,
	INSN_BUG,
	INSN_NOP,
	INSN_STAC,