aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/kernel/Makefile9
-rw-r--r--arch/powerpc/kernel/entry_64.S58
-rw-r--r--arch/powerpc/kernel/ftrace.c79
-rw-r--r--arch/powerpc/kernel/process.c16
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S1
6 files changed, 154 insertions, 10 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index ccdd8de3c558..e122d241f17d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -111,6 +111,7 @@ config PPC
111 select HAVE_FTRACE_MCOUNT_RECORD 111 select HAVE_FTRACE_MCOUNT_RECORD
112 select HAVE_DYNAMIC_FTRACE 112 select HAVE_DYNAMIC_FTRACE
113 select HAVE_FUNCTION_TRACER 113 select HAVE_FUNCTION_TRACER
114 select HAVE_FUNCTION_GRAPH_TRACER if !DYNAMIC_FTRACE && PPC64
114 select ARCH_WANT_OPTIONAL_GPIOLIB 115 select ARCH_WANT_OPTIONAL_GPIOLIB
115 select HAVE_IDE 116 select HAVE_IDE
116 select HAVE_IOREMAP_PROT 117 select HAVE_IOREMAP_PROT
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index d15992119085..583ba6493a62 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -18,12 +18,10 @@ CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog
18CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog 18CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog
19CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog 19CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog
20CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog 20CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog
21 21# do not trace tracer code
22ifdef CONFIG_DYNAMIC_FTRACE
23# dynamic ftrace setup.
24CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog 22CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog
25endif 23# timers used by tracing
26 24CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog
27endif 25endif
28 26
29obj-y := cputable.o ptrace.o syscalls.o \ 27obj-y := cputable.o ptrace.o syscalls.o \
@@ -95,6 +93,7 @@ obj-$(CONFIG_AUDIT) += audit.o
95obj64-$(CONFIG_AUDIT) += compat_audit.o 93obj64-$(CONFIG_AUDIT) += compat_audit.o
96 94
97obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o 95obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
96obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
98 97
99obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o 98obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
100 99
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 383ed6eb0085..a32699e74c3c 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -931,13 +931,65 @@ _GLOBAL(_mcount)
931 ld r5,0(r5) 931 ld r5,0(r5)
932 mtctr r5 932 mtctr r5
933 bctrl 933 bctrl
934
935 nop 934 nop
935
936
937#ifdef CONFIG_FUNCTION_GRAPH_TRACER
938 b ftrace_graph_caller
939#endif
936 ld r0, 128(r1) 940 ld r0, 128(r1)
937 mtlr r0 941 mtlr r0
938 addi r1, r1, 112 942 addi r1, r1, 112
939_GLOBAL(ftrace_stub) 943_GLOBAL(ftrace_stub)
940 blr 944 blr
941 945
942#endif 946#endif /* CONFIG_DYNAMIC_FTRACE */
943#endif 947
948#ifdef CONFIG_FUNCTION_GRAPH_TRACER
949ftrace_graph_caller:
950 /* load r4 with local address */
951 ld r4, 128(r1)
952 subi r4, r4, MCOUNT_INSN_SIZE
953
954 /* get the parent address */
955 ld r11, 112(r1)
956 addi r3, r11, 16
957
958 bl .prepare_ftrace_return
959 nop
960
961 ld r0, 128(r1)
962 mtlr r0
963 addi r1, r1, 112
964 blr
965
966_GLOBAL(return_to_handler)
967 /* need to save return values */
968 std r4, -32(r1)
969 std r3, -24(r1)
970 /* save TOC */
971 std r2, -16(r1)
972 std r31, -8(r1)
973 mr r31, r1
974 stdu r1, -112(r1)
975
976 /* update the TOC */
977 LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler)
978 ld r2, 8(r4)
979
980 bl .ftrace_return_to_handler
981 nop
982
983 /* return value has real return address */
984 mtlr r3
985
986 ld r1, 0(r1)
987 ld r4, -32(r1)
988 ld r3, -24(r1)
989 ld r2, -16(r1)
990 ld r31, -8(r1)
991
992 /* Jump back to real return address */
993 blr
994#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
995#endif /* CONFIG_FUNCTION_TRACER */
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 4112175183d3..c9b1547f65a5 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -5,6 +5,9 @@
5 * 5 *
6 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. 6 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
7 * 7 *
8 * Added function graph tracer code, taken from x86 that was written
9 * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
10 *
8 */ 11 */
9 12
10#include <linux/spinlock.h> 13#include <linux/spinlock.h>
@@ -20,8 +23,6 @@
20#include <asm/code-patching.h> 23#include <asm/code-patching.h>
21#include <asm/ftrace.h> 24#include <asm/ftrace.h>
22 25
23static unsigned int ftrace_nop = PPC_NOP_INSTR;
24
25#ifdef CONFIG_PPC32 26#ifdef CONFIG_PPC32
26# define GET_ADDR(addr) addr 27# define GET_ADDR(addr) addr
27#else 28#else
@@ -29,6 +30,8 @@ static unsigned int ftrace_nop = PPC_NOP_INSTR;
29# define GET_ADDR(addr) (*(unsigned long *)addr) 30# define GET_ADDR(addr) (*(unsigned long *)addr)
30#endif 31#endif
31 32
33#ifdef CONFIG_DYNAMIC_FTRACE
34static unsigned int ftrace_nop = PPC_NOP_INSTR;
32 35
33static unsigned int ftrace_calc_offset(long ip, long addr) 36static unsigned int ftrace_calc_offset(long ip, long addr)
34{ 37{
@@ -525,3 +528,75 @@ int __init ftrace_dyn_arch_init(void *data)
525 528
526 return 0; 529 return 0;
527} 530}
531#endif /* CONFIG_DYNAMIC_FTRACE */
532
533#ifdef CONFIG_FUNCTION_GRAPH_TRACER
534
535/*
536 * Hook the return address and push it in the stack of return addrs
537 * in current thread info.
538 */
539void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
540{
541 unsigned long old;
542 unsigned long long calltime;
543 int faulted;
544 struct ftrace_graph_ent trace;
545 unsigned long return_hooker = (unsigned long)
546 &return_to_handler;
547
548 if (unlikely(atomic_read(&current->tracing_graph_pause)))
549 return;
550
551 return_hooker = GET_ADDR(return_hooker);
552
553 /*
554 * Protect against fault, even if it shouldn't
555 * happen. This tool is too much intrusive to
556 * ignore such a protection.
557 */
558 asm volatile(
559 "1: " PPC_LL "%[old], 0(%[parent])\n"
560 "2: " PPC_STL "%[return_hooker], 0(%[parent])\n"
561 " li %[faulted], 0\n"
562 "3:"
563
564 ".section .fixup, \"ax\"\n"
565 "4: li %[faulted], 1\n"
566 " b 3b\n"
567 ".previous\n"
568
569 ".section __ex_table,\"a\"\n"
570 PPC_LONG_ALIGN "\n"
571 PPC_LONG "1b,4b\n"
572 PPC_LONG "2b,4b\n"
573 ".previous"
574
575 : [old] "=r" (old), [faulted] "=r" (faulted)
576 : [parent] "r" (parent), [return_hooker] "r" (return_hooker)
577 : "memory"
578 );
579
580 if (unlikely(faulted)) {
581 ftrace_graph_stop();
582 WARN_ON(1);
583 return;
584 }
585
586 calltime = cpu_clock(raw_smp_processor_id());
587
588 if (ftrace_push_return_trace(old, calltime,
589 self_addr, &trace.depth) == -EBUSY) {
590 *parent = old;
591 return;
592 }
593
594 trace.func = self_addr;
595
596 /* Only trace if the calling function expects to */
597 if (!ftrace_graph_entry(&trace)) {
598 current->curr_ret_stack--;
599 *parent = old;
600 }
601}
602#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index fb7049c054c0..8ede428e76c0 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -33,6 +33,7 @@
33#include <linux/mqueue.h> 33#include <linux/mqueue.h>
34#include <linux/hardirq.h> 34#include <linux/hardirq.h>
35#include <linux/utsname.h> 35#include <linux/utsname.h>
36#include <linux/ftrace.h>
36#include <linux/kernel_stat.h> 37#include <linux/kernel_stat.h>
37 38
38#include <asm/pgtable.h> 39#include <asm/pgtable.h>
@@ -1008,6 +1009,14 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
1008 unsigned long sp, ip, lr, newsp; 1009 unsigned long sp, ip, lr, newsp;
1009 int count = 0; 1010 int count = 0;
1010 int firstframe = 1; 1011 int firstframe = 1;
1012#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1013 int curr_frame = current->curr_ret_stack;
1014 extern void return_to_handler(void);
1015 unsigned long addr = (unsigned long)return_to_handler;
1016#ifdef CONFIG_PPC64
1017 addr = *(unsigned long*)addr;
1018#endif
1019#endif
1011 1020
1012 sp = (unsigned long) stack; 1021 sp = (unsigned long) stack;
1013 if (tsk == NULL) 1022 if (tsk == NULL)
@@ -1030,6 +1039,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
1030 ip = stack[STACK_FRAME_LR_SAVE]; 1039 ip = stack[STACK_FRAME_LR_SAVE];
1031 if (!firstframe || ip != lr) { 1040 if (!firstframe || ip != lr) {
1032 printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); 1041 printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip);
1042#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1043 if (ip == addr && curr_frame >= 0) {
1044 printk(" (%pS)",
1045 (void *)current->ret_stack[curr_frame].ret);
1046 curr_frame--;
1047 }
1048#endif
1033 if (firstframe) 1049 if (firstframe)
1034 printk(" (unreliable)"); 1050 printk(" (unreliable)");
1035 printk("\n"); 1051 printk("\n");
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 161b9b9691f0..895af44bf1f4 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -58,6 +58,7 @@ SECTIONS
58 SCHED_TEXT 58 SCHED_TEXT
59 LOCK_TEXT 59 LOCK_TEXT
60 KPROBES_TEXT 60 KPROBES_TEXT
61 IRQENTRY_TEXT
61 62
62#ifdef CONFIG_PPC32 63#ifdef CONFIG_PPC32
63 *(.got1) 64 *(.got1)