ppc64le FTRACE_WITH_REGS implementation
PATCH v3 1/8 ppc64le FTRACE_WITH_REGS implementation
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:
- enhance _mcount with a stub to support call sites generated by -mprofile-kernel. This is backward-compatible.
- 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.
--- arch/powerpc/include/asm/ftrace.h | 5 ++ arch/powerpc/kernel/entry_64.S | 113 +++++++++++++++++++++++++++++++++++++- arch/powerpc/kernel/ftrace.c | 72 +++++++++++++++++++++--- arch/powerpc/kernel/module_64.c | 39 ++++++++++++- 4 files changed, 217 insertions(+), 12 deletions(-)
arch/powerpc/include/asm/ftrace.h +5 -0
@@ -46,6 +46,8 @@extern void _mcount (void );#ifdef CONFIG_DYNAMIC_FTRACE +# define FTRACE_ADDR ((unsigned long)ftrace_caller) +# define FTRACE_REGS_ADDR FTRACE_ADDRstatic 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 +#define ARCH_SUPPORTS_FTRACE_OPS 1 +#endif #endif #if defined(CONFIG_FTRACE_SYSCALLS ) && defined(CONFIG_PPC64 ) && !defined(__ASSEMBLY__)
arch/powerpc/kernel/entry_64.S +112 -1
142 lines not on this page · raw message
arch/powerpc/kernel/ftrace.c +64 -8
120 lines not on this page · raw message
arch/powerpc/kernel/module_64.c +36 -3
@@ -138,12 +138,21 @@ static u32 ppc64_stub_insns[] = {0x4e800420 /* bctr */ }; +/* 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) +#ifdef CONFIG_DYNAMIC_FTRACE static u32 ppc64_stub_mask[] = {0xffff0000 ,0xffff0000 , -0xffffffff , +0x00000000 ,0xffffffff , #if !defined(_CALL_ELF) || _CALL_ELF != 2 0xffffffff,
@@ -170,6 +179,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; }
@@ -475,6 +487,19 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,static int restore_r2 (u32 *instruction,struct module *me) {if (*instruction !=PPC_INST_NOP ) { + +/* -mprofile_kernel sequence starting with +* mflr r0; std r0, LRSAVE(r1) +*/ +if (instruction[-3 ] ==0x7c0802a6 && + instruction[-2 ] ==0xf8010010 ) { +/* Nothing to be done here, it's an _mcount +* call location and r2 will have to be +* restored in the _mcount function. +*/ +return 2 ; + }; +pr_err ("%s: Expect noop after relocate, got %08x\n" , me->name, *instruction);return 0 ;
@@ -490,7 +515,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,unsigned int relsec, struct module *me) { - unsigned int i; + unsigned int i, r2;Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;Elf64_Sym *sym;unsigned long *location;
@@ -603,8 +628,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, value =stub_for_addr (sechdrs, value, me);if (!value)return -ENOENT ; -if (!restore_r2 ((u32 *)location +1 , me)) + r2 =restore_r2 ((u32 *)location +1 , me); +if (!r2)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);
@@ -665,6 +694,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 ;
Signature · 1 line
1.8.5.6