Commit db7adcfd authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

x86/alternatives: Introduce int3_emulate_jcc()

Move the kprobe Jcc emulation into int3_emulate_jcc() so it can be
used by more code -- specifically static_call() will need this.
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
Reviewed-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Link: https://lore.kernel.org/r/20230123210607.057678245@infradead.org
parent 5d1dd961
...@@ -184,6 +184,37 @@ void int3_emulate_ret(struct pt_regs *regs) ...@@ -184,6 +184,37 @@ void int3_emulate_ret(struct pt_regs *regs)
unsigned long ip = int3_emulate_pop(regs); unsigned long ip = int3_emulate_pop(regs);
int3_emulate_jmp(regs, ip); int3_emulate_jmp(regs, ip);
} }
static __always_inline
void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp)
{
static const unsigned long jcc_mask[6] = {
[0] = X86_EFLAGS_OF,
[1] = X86_EFLAGS_CF,
[2] = X86_EFLAGS_ZF,
[3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
[4] = X86_EFLAGS_SF,
[5] = X86_EFLAGS_PF,
};
bool invert = cc & 1;
bool match;
if (cc < 0xc) {
match = regs->flags & jcc_mask[cc >> 1];
} else {
match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
if (cc >= 0xe)
match = match || (regs->flags & X86_EFLAGS_ZF);
}
if ((match && !invert) || (!match && invert))
ip += disp;
int3_emulate_jmp(regs, ip);
}
#endif /* !CONFIG_UML_X86 */ #endif /* !CONFIG_UML_X86 */
#endif /* _ASM_X86_TEXT_PATCHING_H */ #endif /* _ASM_X86_TEXT_PATCHING_H */
...@@ -460,50 +460,26 @@ static void kprobe_emulate_call(struct kprobe *p, struct pt_regs *regs) ...@@ -460,50 +460,26 @@ static void kprobe_emulate_call(struct kprobe *p, struct pt_regs *regs)
} }
NOKPROBE_SYMBOL(kprobe_emulate_call); NOKPROBE_SYMBOL(kprobe_emulate_call);
static nokprobe_inline static void kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs)
void __kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs, bool cond)
{ {
unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size; unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
if (cond) ip += p->ainsn.rel32;
ip += p->ainsn.rel32;
int3_emulate_jmp(regs, ip); int3_emulate_jmp(regs, ip);
} }
static void kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs)
{
__kprobe_emulate_jmp(p, regs, true);
}
NOKPROBE_SYMBOL(kprobe_emulate_jmp); NOKPROBE_SYMBOL(kprobe_emulate_jmp);
static const unsigned long jcc_mask[6] = {
[0] = X86_EFLAGS_OF,
[1] = X86_EFLAGS_CF,
[2] = X86_EFLAGS_ZF,
[3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
[4] = X86_EFLAGS_SF,
[5] = X86_EFLAGS_PF,
};
static void kprobe_emulate_jcc(struct kprobe *p, struct pt_regs *regs) static void kprobe_emulate_jcc(struct kprobe *p, struct pt_regs *regs)
{ {
bool invert = p->ainsn.jcc.type & 1; unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
bool match;
if (p->ainsn.jcc.type < 0xc) { int3_emulate_jcc(regs, p->ainsn.jcc.type, ip, p->ainsn.rel32);
match = regs->flags & jcc_mask[p->ainsn.jcc.type >> 1];
} else {
match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
if (p->ainsn.jcc.type >= 0xe)
match = match || (regs->flags & X86_EFLAGS_ZF);
}
__kprobe_emulate_jmp(p, regs, (match && !invert) || (!match && invert));
} }
NOKPROBE_SYMBOL(kprobe_emulate_jcc); NOKPROBE_SYMBOL(kprobe_emulate_jcc);
static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs) static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs)
{ {
unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
bool match; bool match;
if (p->ainsn.loop.type != 3) { /* LOOP* */ if (p->ainsn.loop.type != 3) { /* LOOP* */
...@@ -531,7 +507,9 @@ static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs) ...@@ -531,7 +507,9 @@ static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs)
else if (p->ainsn.loop.type == 1) /* LOOPE */ else if (p->ainsn.loop.type == 1) /* LOOPE */
match = match && (regs->flags & X86_EFLAGS_ZF); match = match && (regs->flags & X86_EFLAGS_ZF);
__kprobe_emulate_jmp(p, regs, match); if (match)
ip += p->ainsn.rel32;
int3_emulate_jmp(regs, ip);
} }
NOKPROBE_SYMBOL(kprobe_emulate_loop); NOKPROBE_SYMBOL(kprobe_emulate_loop);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment