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 ? &regs->r8 : &regs->ax;
> +     case 0x51:
> +             return auprobe->push.rex_prefix ? &regs->r9 : &regs->cx;
> +     case 0x52:
> +             return auprobe->push.rex_prefix ? &regs->r10 : &regs->dx;
> +     case 0x53:
> +             return auprobe->push.rex_prefix ? &regs->r11 : &regs->bx;
> +     case 0x54:
> +             return auprobe->push.rex_prefix ? &regs->r12 : &regs->sp;
> +     case 0x55:
> +             return auprobe->push.rex_prefix ? &regs->r13 : &regs->bp;
> +     case 0x56:
> +             return auprobe->push.rex_prefix ? &regs->r14 : &regs->si;
> +     }
> +
> +     /* opc1 0x57 */
> +     return auprobe->push.rex_prefix ? &regs->r15 : &regs->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

Reply via email to