[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <063D6719AE5E284EB5DD2968C1650D6DD00B73C7@AcuExch.aculab.com>
Date: Thu, 9 Nov 2017 11:26:10 +0000
From: David Laight <David.Laight@...LAB.COM>
To: 'Yonghong Song' <yhs@...com>,
"mingo@...nel.org" <mingo@...nel.org>,
"tglx@...utronix.de" <tglx@...utronix.de>,
"oleg@...hat.com" <oleg@...hat.com>,
"peterz@...radead.org" <peterz@...radead.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
"x86@...nel.org" <x86@...nel.org>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>,
"ast@...com" <ast@...com>
CC: "kernel-team@...com" <kernel-team@...com>
Subject: RE: [PATCH x86 v2] uprobe: emulate push insns for uprobe on x86
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
Powered by blists - more mailing lists