Unverified Commit 3f6af508 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!977 [sync] PR-968: Fix ORC unwinder on paravirt {save,restore}_fl

Merge Pull Request from: @openeuler-sync-bot 
 

Origin pull request: 
https://gitee.com/openeuler/kernel/pulls/968 
 
PR sync from:  Chen Zhongjin <chenzhongjin@huawei.com>
 https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/thread/C2NOJBSCQVMEFEIEDAK3YKPNYQ67TO7J/ 
ISSUE: gitee.com/openeuler/kernel/issues/I6DK3O

Chen Zhongjin (2):
  x86/unwind: Fix orc entry for paravirt {save,restore}_fl
  x86/unwind: Fix check_paravirt() calls orc_find() before declaration


-- 
2.17.1
 
 
Link:https://gitee.com/openeuler/kernel/pulls/977

 

Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents b8e1d215 b46958a8
Loading
Loading
Loading
Loading
+44 −1
Original line number Diff line number Diff line
@@ -77,9 +77,9 @@ static struct orc_entry *orc_module_find(unsigned long ip)
}
#endif

#ifdef CONFIG_DYNAMIC_FTRACE
static struct orc_entry *orc_find(unsigned long ip);

#ifdef CONFIG_DYNAMIC_FTRACE
/*
 * Ftrace dynamic trampolines do not have orc entries of their own.
 * But they are copies of the ftrace entries that are static and
@@ -146,6 +146,34 @@ static struct orc_entry orc_fp_entry = {
	.end		= 0,
};

#ifdef CONFIG_PARAVIRT_XXL
static bool check_paravirt(struct unwind_state *state, struct orc_entry *orc)
{
	u8 *ip = (u8 *)state->ip;

	/*
	 * In paravirt_patch.c, patched paravirt opcode should be:
	 * pushfq; popq %rax // 0x9c 0x58
	 * pushq %rdi; popfq // 0x57 0x9d
	 *
	 * Error unwinding only happens when:
	 * 1. In irq or preempt context.
	 * 2. Current insn is popq, and it doesn't change orc.
	 * 3. Last insn doesn't change orc, checking it first to
	 *    promise ip - 1 is valid.
	 * 4. Last byte fits pushf.
	 */
	if (state->regs && orc->type == UNWIND_HINT_TYPE_CALL &&
		(ip[0] == 0x58 || ip[0] == 0x9d) &&
		orc == orc_find((unsigned long)(ip + 1)) &&
		orc == orc_find((unsigned long)(ip - 1)) &&
		(ip[-1] == 0x9c || ip[-1] == 0x57))
		return true;

	return false;
}
#endif

static struct orc_entry *orc_find(unsigned long ip)
{
	static struct orc_entry *orc;
@@ -425,6 +453,9 @@ bool unwind_next_frame(struct unwind_state *state)
	enum stack_type prev_type = state->stack_info.type;
	struct orc_entry *orc;
	bool indirect = false;
#ifdef CONFIG_PARAVIRT_XXL
	struct orc_entry para_orc;
#endif

	if (unwind_done(state))
		return false;
@@ -457,6 +488,18 @@ bool unwind_next_frame(struct unwind_state *state)
		state->error = true;
	}

#ifdef CONFIG_PARAVIRT_XXL
	/*
	 * When hitting paravirt POP insn, the orc entry should add
	 * one slot for PUSH insn.
	 */
	if (!state->error && check_paravirt(state, orc)) {
		para_orc = *orc;
		para_orc.sp_offset += sizeof(long);
		orc = &para_orc;
	}
#endif

	/* End-of-stack check for kernel threads: */
	if (orc->sp_reg == ORC_REG_UNDEFINED) {
		if (!orc->end)