From: Yonghong Song > Sent: 09 November 2017 00:55 > > Uprobe is a tracing mechanism for userspace programs. > Typical uprobe will incur overhead of two traps. > First trap is caused by replaced trap insn, and > the second trap is to execute the original displaced > insn in user space. > > To reduce the overhead, kernel provides hooks > for architectures to emulate the original insn > and skip the second trap. In x86, emulation > is done for certain branch insns. > > This patch extends the emulation to "push <reg>" > insns. These insns are typical in the beginning > of the function. For example, bcc ... > diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h > index 74f4c2f..f9d2b43 100644 > --- a/arch/x86/include/asm/uprobes.h > +++ b/arch/x86/include/asm/uprobes.h > @@ -33,6 +33,11 @@ typedef u8 uprobe_opcode_t; ... > @@ -53,6 +59,10 @@ struct arch_uprobe { > u8 fixups; > u8 ilen; > } defparam; > + struct { > + u8 rex_prefix;
Just call this 'reg_high' and set to 0 or 1. > + u8 opc1; > + } push; > }; > }; > > diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c > index a3755d2..5ace65c 100644 > --- a/arch/x86/kernel/uprobes.c > +++ b/arch/x86/kernel/uprobes.c > @@ -640,11 +640,71 @@ static bool check_jmp_cond(struct arch_uprobe *auprobe, > struct pt_regs *regs) > #undef COND > #undef CASE_COND > > -static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs > *regs) > +static unsigned long *get_push_reg_ptr(struct arch_uprobe *auprobe, > + struct pt_regs *regs) > { > - unsigned long new_ip = regs->ip += auprobe->branch.ilen; > - unsigned long offs = (long)auprobe->branch.offs; > +#if defined(CONFIG_X86_64) > + switch (auprobe->push.opc1) { > + case 0x50: > + return auprobe->push.rex_prefix ? ®s->r8 : ®s->ax; > + case 0x51: > + return auprobe->push.rex_prefix ? ®s->r9 : ®s->cx; > + case 0x52: > + return auprobe->push.rex_prefix ? ®s->r10 : ®s->dx; > + case 0x53: > + return auprobe->push.rex_prefix ? ®s->r11 : ®s->bx; > + case 0x54: > + return auprobe->push.rex_prefix ? ®s->r12 : ®s->sp; > + case 0x55: > + return auprobe->push.rex_prefix ? ®s->r13 : ®s->bp; > + case 0x56: > + return auprobe->push.rex_prefix ? ®s->r14 : ®s->si; > + } > + > + /* opc1 0x57 */ > + return auprobe->push.rex_prefix ? ®s->r15 : ®s->di; The bottom of that switch statement is horrid.... Actually why can't you sort out this address in the code that sets up 'reg_prefix' (etc); David