OSDN Git Service

s390/ftrace: hotpatch support for function tracing
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Fri, 9 Jan 2015 12:08:28 +0000 (13:08 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 29 Jan 2015 08:19:25 +0000 (09:19 +0100)
Make use of gcc's hotpatch support to generate better code for ftrace
function tracing.
The generated code now contains only a six byte nop in each function
prologue instead of a 24 byte code block which will be runtime patched to
support function tracing.
With the new code generation the runtime overhead for supporting function
tracing is close to zero, while the original code did show a significant
performance impact.

Acked-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/ftrace.h
arch/s390/kernel/Makefile
arch/s390/kernel/ftrace.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/mcount.S
scripts/recordmcount.pl

index 7eba5b5..8d11bab 100644 (file)
@@ -117,7 +117,6 @@ config S390
        select HAVE_BPF_JIT if 64BIT && PACK_STACK
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
-       select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DYNAMIC_FTRACE if 64BIT
        select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
index e742ec5..acb6859 100644 (file)
@@ -87,6 +87,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
 cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
 endif
 
+ifdef CONFIG_FUNCTION_TRACER
+# make use of hotpatch feature if the compiler supports it
+cc_hotpatch    := -mhotpatch=0,3
+ifeq ($(call cc-option-yn,$(cc_hotpatch)),y)
+CC_FLAGS_FTRACE := $(cc_hotpatch)
+KBUILD_AFLAGS  += -DCC_USING_HOTPATCH
+KBUILD_CFLAGS  += -DCC_USING_HOTPATCH
+endif
+endif
+
 KBUILD_CFLAGS  += -mbackchain -msoft-float $(cflags-y)
 KBUILD_CFLAGS  += -pipe -fno-strength-reduce -Wno-sign-compare
 KBUILD_AFLAGS  += $(aflags-y)
index abb618f..836c562 100644 (file)
@@ -3,8 +3,12 @@
 
 #define ARCH_SUPPORTS_FTRACE_OPS 1
 
+#ifdef CC_USING_HOTPATCH
+#define MCOUNT_INSN_SIZE       6
+#else
 #define MCOUNT_INSN_SIZE       24
 #define MCOUNT_RETURN_FIXUP    18
+#endif
 
 #ifndef __ASSEMBLY__
 
@@ -37,18 +41,29 @@ struct ftrace_insn {
 static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
        /* jg .+24 */
        insn->opc = 0xc0f4;
        insn->disp = MCOUNT_INSN_SIZE / 2;
 #endif
+#endif
 }
 
 static inline int is_ftrace_nop(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_HOTPATCH
+       if (insn->disp == 0)
+               return 1;
+#else
        if (insn->disp == MCOUNT_INSN_SIZE / 2)
                return 1;
 #endif
+#endif
        return 0;
 }
 
index 204c43a..31fab26 100644 (file)
@@ -4,8 +4,8 @@
 
 ifdef CONFIG_FUNCTION_TRACER
 # Don't trace early setup code and tracing code
-CFLAGS_REMOVE_early.o = -pg
-CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
 endif
 
 #
index 3dabcae..82c1989 100644 (file)
  *     lg      %r14,8(%r15)            # offset 18
  * The jg instruction branches to offset 24 to skip as many instructions
  * as possible.
+ * In case we use gcc's hotpatch feature the original and also the disabled
+ * function prologue contains only a single six byte instruction and looks
+ * like this:
+ * >   brcl    0,0                     # offset 0
+ * To enable ftrace the code gets patched like above and afterwards looks
+ * like this:
+ * >   brasl   %r0,ftrace_caller       # offset 0
  */
 
 unsigned long ftrace_plt;
@@ -64,9 +71,15 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
        if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
        if (addr == MCOUNT_ADDR) {
-               /* Initial code replacement; we expect to see stg r14,8(r15) */
+               /* Initial code replacement */
+#ifdef CC_USING_HOTPATCH
+               /* We expect to see brcl 0,0 */
+               ftrace_generate_nop_insn(&orig);
+#else
+               /* We expect to see stg r14,8(r15) */
                orig.opc = 0xe3e0;
                orig.disp = 0xf0080024;
+#endif
                ftrace_generate_nop_insn(&new);
        } else if (old.opc == BREAKPOINT_INSTRUCTION) {
                /*
index 1e4c710..f516edc 100644 (file)
@@ -69,7 +69,8 @@ static void copy_instruction(struct kprobe *p)
                /*
                 * If kprobes patches the instruction that is morphed by
                 * ftrace make sure that kprobes always sees the branch
-                * "jg .+24" that skips the mcount block
+                * "jg .+24" that skips the mcount block or the "brcl 0,0"
+                * in case of hotpatch.
                 */
                ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
                p->ainsn.is_ftrace_insn = 1;
index b6dfc5b..e499370 100644 (file)
@@ -27,7 +27,9 @@ ENTRY(ftrace_caller)
        .globl  ftrace_regs_caller
        .set    ftrace_regs_caller,ftrace_caller
        lgr     %r1,%r15
+#ifndef CC_USING_HOTPATCH
        aghi    %r0,MCOUNT_RETURN_FIXUP
+#endif
        aghi    %r15,-STACK_FRAME_SIZE
        stg     %r1,__SF_BACKCHAIN(%r15)
        stg     %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
index 56ea99a..be39be0 100755 (executable)
@@ -242,8 +242,13 @@ if ($arch eq "x86_64") {
     $cc .= " -m32";
 
 } elsif ($arch eq "s390" && $bits == 64) {
-    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
-    $mcount_adjust = -14;
+    if ($cc =~ /-DCC_USING_HOTPATCH/) {
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
+       $mcount_adjust = 0;
+    } else {
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
+       $mcount_adjust = -14;
+    }
     $alignment = 8;
     $type = ".quad";
     $ld .= " -m elf64_s390";