From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753177AbbKZKE2 (ORCPT ); Thu, 26 Nov 2015 05:04:28 -0500 Received: from mail-yk0-f182.google.com ([209.85.160.182]:36518 "EHLO mail-yk0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750934AbbKZKEU (ORCPT ); Thu, 26 Nov 2015 05:04:20 -0500 MIME-Version: 1.0 X-Originating-IP: [195.54.192.103] In-Reply-To: <20151125172902.82C6C69260@newverein.lst.de> References: <20151125172608.9588569260@newverein.lst.de> <20151125172902.82C6C69260@newverein.lst.de> Date: Thu, 26 Nov 2015 13:04:19 +0300 Message-ID: Subject: Re: [PATCH v4 2/9] ppc64le FTRACE_WITH_REGS implementation From: Denis Kirjanov To: Torsten Duwe Cc: Steven Rostedt , Michael Ellerman , Jiri Kosina , linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, live-patching@vger.kernel.org Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 11/25/15, Torsten Duwe wrote: > Implement FTRACE_WITH_REGS for powerpc64, on ELF ABI v2. > Initial work started by Vojtech Pavlik, used with permission. > > * arch/powerpc/kernel/entry_64.S: > - Implement an effective ftrace_caller that works from > within the kernel binary as well as from modules. > * arch/powerpc/kernel/ftrace.c: > - be prepared to deal with ppc64 ELF ABI v2, especially > calls to _mcount that result from gcc -mprofile-kernel > - a little more error verbosity > * arch/powerpc/kernel/module_64.c: > - do not save the TOC pointer on the trampoline when the > destination is ftrace_caller. This trampoline jump happens from > a function prologue before a new stack frame is set up, so bad > things may happen otherwise... > - relax is_module_trampoline() to recognise the modified > trampoline. > > Signed-off-by: Torsten Duwe > --- > arch/powerpc/include/asm/ftrace.h | 5 +++ > arch/powerpc/kernel/entry_64.S | 77 > +++++++++++++++++++++++++++++++++++++++ > arch/powerpc/kernel/ftrace.c | 60 +++++++++++++++++++++++++++--- > arch/powerpc/kernel/module_64.c | 25 ++++++++++++- > 4 files changed, 160 insertions(+), 7 deletions(-) > > diff --git a/arch/powerpc/include/asm/ftrace.h > b/arch/powerpc/include/asm/ftrace.h > index ef89b14..50ca758 100644 > --- a/arch/powerpc/include/asm/ftrace.h > +++ b/arch/powerpc/include/asm/ftrace.h > @@ -46,6 +46,8 @@ > extern void _mcount(void); > > #ifdef CONFIG_DYNAMIC_FTRACE > +# define FTRACE_ADDR ((unsigned long)ftrace_caller) > +# define FTRACE_REGS_ADDR FTRACE_ADDR > static inline unsigned long ftrace_call_adjust(unsigned long addr) > { > /* reloction of mcount call site is the same as the address */ > @@ -58,6 +60,9 @@ struct dyn_arch_ftrace { > #endif /* CONFIG_DYNAMIC_FTRACE */ > #endif /* __ASSEMBLY__ */ > > +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS > +#define ARCH_SUPPORTS_FTRACE_OPS 1 > +#endif > #endif > > #if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) && > !defined(__ASSEMBLY__) > diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S > index 8d56b16..3309dd8 100644 > --- a/arch/powerpc/kernel/entry_64.S > +++ b/arch/powerpc/kernel/entry_64.S Linux style for comments is the C89. Please update entry_64.S > @@ -1212,6 +1212,7 @@ _GLOBAL(_mcount) > mtlr r0 > bctr > > +#ifndef CC_USING_MPROFILE_KERNEL > _GLOBAL_TOC(ftrace_caller) > /* Taken from output of objdump from lib64/glibc */ > mflr r3 > @@ -1233,6 +1234,82 @@ _GLOBAL(ftrace_graph_stub) > ld r0, 128(r1) > mtlr r0 > addi r1, r1, 112 > +#else > +_GLOBAL(ftrace_caller) > +#if defined(_CALL_ELF) && _CALL_ELF == 2 > + mflr r0 > + bl 2f > +2: mflr r12 > + mtlr r0 > + mr r0,r2 // save callee's TOC > + addis r2,r12,(.TOC.-ftrace_caller-8)@ha > + addi r2,r2,(.TOC.-ftrace_caller-8)@l > +#else > + mr r0,r2 > +#endif > + ld r12,LRSAVE(r1) // get caller's address > + > + stdu r1,-SWITCH_FRAME_SIZE(r1) > + > + std r12, _LINK(r1) > + SAVE_8GPRS(0,r1) > + std r0, 24(r1) // save TOC > + SAVE_8GPRS(8,r1) > + SAVE_8GPRS(16,r1) > + SAVE_8GPRS(24,r1) > + > + addis r3,r2,function_trace_op@toc@ha > + addi r3,r3,function_trace_op@toc@l > + ld r5,0(r3) > + > + mflr r3 > + std r3, _NIP(r1) > + std r3, 16(r1) > + subi r3, r3, MCOUNT_INSN_SIZE > + mfmsr r4 > + std r4, _MSR(r1) > + mfctr r4 > + std r4, _CTR(r1) > + mfxer r4 > + std r4, _XER(r1) > + mr r4, r12 > + addi r6, r1 ,STACK_FRAME_OVERHEAD > + > +.globl ftrace_call > +ftrace_call: > + bl ftrace_stub > + nop > + > + ld r3, _NIP(r1) > + mtlr r3 > + > + REST_8GPRS(0,r1) > + REST_8GPRS(8,r1) > + REST_8GPRS(16,r1) > + REST_8GPRS(24,r1) > + > + addi r1, r1, SWITCH_FRAME_SIZE > + > + ld r12, LRSAVE(r1) // get caller's address > + mtlr r12 > + mr r2,r0 // restore callee's TOC > + > +#ifdef CONFIG_FUNCTION_GRAPH_TRACER > + stdu r1, -112(r1) > +.globl ftrace_graph_call > +ftrace_graph_call: > + b ftrace_graph_stub > +_GLOBAL(ftrace_graph_stub) > + addi r1, r1, 112 > +#endif > + > + mflr r0 // move this LR to CTR > + mtctr r0 > + > + ld r0,LRSAVE(r1) // restore callee's lr at _mcount site > + mtlr r0 > + bctr // jump after _mcount site > +#endif /* CC_USING_MPROFILE_KERNEL */ > _GLOBAL(ftrace_stub) > blr > #else > diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c > index 080c525..310137f 100644 > --- a/arch/powerpc/kernel/ftrace.c > +++ b/arch/powerpc/kernel/ftrace.c > @@ -61,8 +61,11 @@ ftrace_modify_code(unsigned long ip, unsigned int old, > unsigned int new) > return -EFAULT; > > /* Make sure it is what we expect it to be */ > - if (replaced != old) > + if (replaced != old) { > + pr_err("%p: replaced (%#x) != old (%#x)", > + (void *)ip, replaced, old); > return -EINVAL; > + } > > /* replace the text with the new text */ > if (patch_instruction((unsigned int *)ip, new)) > @@ -106,14 +109,16 @@ static int > __ftrace_make_nop(struct module *mod, > struct dyn_ftrace *rec, unsigned long addr) > { > - unsigned int op; > + unsigned int op, op0, op1, pop; > unsigned long entry, ptr; > unsigned long ip = rec->ip; > void *tramp; > > /* read where this goes */ > - if (probe_kernel_read(&op, (void *)ip, sizeof(int))) > + if (probe_kernel_read(&op, (void *)ip, sizeof(int))) { > + pr_err("Fetching opcode failed.\n"); > return -EFAULT; > + } > > /* Make sure that that this is still a 24bit jump */ > if (!is_bl_op(op)) { > @@ -158,10 +163,46 @@ __ftrace_make_nop(struct module *mod, > * > * Use a b +8 to jump over the load. > */ > - op = 0x48000008; /* b +8 */ > > - if (patch_instruction((unsigned int *)ip, op)) > + pop = 0x48000008; /* b +8 */ > + > + /* > + * Check what is in the next instruction. We can see ld r2,40(r1), but > + * on first pass after boot we will see mflr r0. > + */ > + if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE)) { > + pr_err("Fetching op failed.\n"); > + return -EFAULT; > + } > + > + if (op != 0xe8410028) { /* ld r2,STACK_OFFSET(r1) */ > + > + if (probe_kernel_read(&op0, (void *)(ip-8), MCOUNT_INSN_SIZE)) { > + pr_err("Fetching op0 failed.\n"); > + return -EFAULT; > + } > + > + if (probe_kernel_read(&op1, (void *)(ip-4), MCOUNT_INSN_SIZE)) { > + pr_err("Fetching op1 failed.\n"); > + return -EFAULT; > + } > + > + /* mflr r0 ; std r0,LRSAVE(r1) */ > + if (op0 != 0x7c0802a6 && op1 != 0xf8010010) { > + pr_err("Unexpected instructions around bl\n" > + "when enabling dynamic ftrace!\t" > + "(%08x,%08x,bl,%08x)\n", op0, op1, op); > + return -EINVAL; > + } > + > + /* When using -mkernel_profile there is no load to jump over */ > + pop = PPC_INST_NOP; > + } > + > + if (patch_instruction((unsigned int *)ip, pop)) { > + pr_err("Patching NOP failed.\n"); > return -EPERM; > + } > > return 0; > } > @@ -287,6 +328,13 @@ int ftrace_make_nop(struct module *mod, > > #ifdef CONFIG_MODULES > #ifdef CONFIG_PPC64 > +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS > +int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, > + unsigned long addr) > +{ > + return ftrace_make_call(rec, addr); > +} > +#endif > static int > __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) > { > @@ -338,7 +386,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long > addr) > > return 0; > } > -#else > +#else /* !CONFIG_PPC64: */ > static int > __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) > { > diff --git a/arch/powerpc/kernel/module_64.c > b/arch/powerpc/kernel/module_64.c > index 0819ce7..9e6902f 100644 > --- a/arch/powerpc/kernel/module_64.c > +++ b/arch/powerpc/kernel/module_64.c > @@ -138,12 +138,25 @@ static u32 ppc64_stub_insns[] = { > 0x4e800420 /* bctr */ > }; > > +#ifdef CC_USING_MPROFILE_KERNEL > +/* In case of _mcount calls or dynamic ftracing, Do not save the > + * current callee's TOC (in R2) again into the original caller's stack > + * frame during this trampoline hop. The stack frame already holds > + * that of the original caller. _mcount and ftrace_caller will take > + * care of this TOC value themselves. > + */ > +#define SQUASH_TOC_SAVE_INSN(trampoline_addr) \ > + (((struct ppc64_stub_entry *)(trampoline_addr))->jump[2] = PPC_INST_NOP) > +#else > +#define SQUASH_TOC_SAVE_INSN(trampoline_addr) > +#endif > + > #ifdef CONFIG_DYNAMIC_FTRACE > > static u32 ppc64_stub_mask[] = { > 0xffff0000, > 0xffff0000, > - 0xffffffff, > + 0x00000000, > 0xffffffff, > #if !defined(_CALL_ELF) || _CALL_ELF != 2 > 0xffffffff, > @@ -170,6 +183,9 @@ bool is_module_trampoline(u32 *p) > if ((insna & mask) != (insnb & mask)) > return false; > } > + if (insns[2] != ppc64_stub_insns[2] && > + insns[2] != PPC_INST_NOP) > + return false; > > return true; > } > @@ -618,6 +634,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, > return -ENOENT; > if (!restore_r2((u32 *)location + 1, me)) > return -ENOEXEC; > + /* Squash the TOC saver for profiler calls */ > + if (!strcmp("_mcount", strtab+sym->st_name)) > + SQUASH_TOC_SAVE_INSN(value); > } else > value += local_entry_offset(sym); > > @@ -678,6 +697,10 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, > me->arch.tramp = stub_for_addr(sechdrs, > (unsigned long)ftrace_caller, > me); > + /* ftrace_caller will take care of the TOC; > + * do not clobber original caller's value. > + */ > + SQUASH_TOC_SAVE_INSN(me->arch.tramp); > #endif > > return 0; > -- > 1.8.5.6 > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev