Commit 67c1d4a2 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

x86/ftrace: Use text_gen_insn()



Replace the ftrace_code_union with the generic text_gen_insn() helper,
which does exactly this.

Tested-by: default avatarAlexei Starovoitov <ast@kernel.org>
Tested-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20191111132457.932808000@infradead.org


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 254d2c04
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -80,7 +80,35 @@ static inline int text_opcode_size(u8 opcode)
	return size;
}

extern void *text_gen_insn(u8 opcode, const void *addr, const void *dest);
union text_poke_insn {
	u8 text[POKE_MAX_OPCODE_SIZE];
	struct {
		u8 opcode;
		s32 disp;
	} __attribute__((packed));
};

static __always_inline
void *text_gen_insn(u8 opcode, const void *addr, const void *dest)
{
	static union text_poke_insn insn; /* per instance */
	int size = text_opcode_size(opcode);

	insn.opcode = opcode;

	if (size > 1) {
		insn.disp = (long)dest - (long)(addr + size);
		if (size == 2) {
			/*
			 * Ensure that for JMP9 the displacement
			 * actually fits the signed byte.
			 */
			BUG_ON((insn.disp >> 31) != (insn.disp >> 7));
		}
	}

	return &insn.text;
}

extern int after_bootmem;
extern __ro_after_init struct mm_struct *poking_mm;
+0 −26
Original line number Diff line number Diff line
@@ -1247,29 +1247,3 @@ void __ref text_poke_bp(void *addr, const void *opcode, size_t len, const void *
	text_poke_loc_init(&tp, addr, opcode, len, emulate);
	text_poke_bp_batch(&tp, 1);
}

union text_poke_insn {
	u8 text[POKE_MAX_OPCODE_SIZE];
	struct {
		u8 opcode;
		s32 disp;
	} __attribute__((packed));
};

void *text_gen_insn(u8 opcode, const void *addr, const void *dest)
{
	static union text_poke_insn insn; /* text_mutex */
	int size = text_opcode_size(opcode);

	lockdep_assert_held(&text_mutex);

	insn.opcode = opcode;

	if (size > 1) {
		insn.disp = (long)dest - (long)(addr + size);
		if (size == 2)
			BUG_ON((insn.disp >> 31) != (insn.disp >> 7));
	}

	return &insn.text;
}
+7 −25
Original line number Diff line number Diff line
@@ -63,24 +63,6 @@ int ftrace_arch_code_modify_post_process(void)
	return 0;
}

union ftrace_code_union {
	char code[MCOUNT_INSN_SIZE];
	struct {
		char op;
		int offset;
	} __attribute__((packed));
};

static const char *ftrace_text_replace(char op, unsigned long ip, unsigned long addr)
{
	static union ftrace_code_union calc;

	calc.op = op;
	calc.offset = (int)(addr - (ip + MCOUNT_INSN_SIZE));

	return calc.code;
}

static const char *ftrace_nop_replace(void)
{
	return ideal_nops[NOP_ATOMIC5];
@@ -88,7 +70,7 @@ static const char *ftrace_nop_replace(void)

static const char *ftrace_call_replace(unsigned long ip, unsigned long addr)
{
	return ftrace_text_replace(CALL_INSN_OPCODE, ip, addr);
	return text_gen_insn(CALL_INSN_OPCODE, (void *)ip, (void *)addr);
}

static int ftrace_verify_code(unsigned long ip, const char *old_code)
@@ -480,20 +462,20 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
/* Return the address of the function the trampoline calls */
static void *addr_from_call(void *ptr)
{
	union ftrace_code_union calc;
	union text_poke_insn call;
	int ret;

	ret = probe_kernel_read(&calc, ptr, MCOUNT_INSN_SIZE);
	ret = probe_kernel_read(&call, ptr, CALL_INSN_SIZE);
	if (WARN_ON_ONCE(ret < 0))
		return NULL;

	/* Make sure this is a call */
	if (WARN_ON_ONCE(calc.op != 0xe8)) {
		pr_warn("Expected e8, got %x\n", calc.op);
	if (WARN_ON_ONCE(call.opcode != CALL_INSN_OPCODE)) {
		pr_warn("Expected E8, got %x\n", call.opcode);
		return NULL;
	}

	return ptr + MCOUNT_INSN_SIZE + calc.offset;
	return ptr + CALL_INSN_SIZE + call.disp;
}

void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
@@ -562,7 +544,7 @@ extern void ftrace_graph_call(void);

static const char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
{
	return ftrace_text_replace(JMP32_INSN_OPCODE, ip, addr);
	return text_gen_insn(JMP32_INSN_OPCODE, (void *)ip, (void *)addr);
}

static int ftrace_mod_jmp(unsigned long ip, void *func)