aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2009-02-08 18:43:36 -0500
committerKyle McMartin <kyle@mcmartin.ca>2009-03-30 22:51:34 -0400
commitd75f054a2cf0614ff63d534ff21ca8eaab41e713 (patch)
treee1fbea035711abf72099ebd01918f5ba3c3cf9ae
parent803094f480aa5b7dd5187a17e6e60ff24721c212 (diff)
parisc: add ftrace (function and graph tracer) functionality
This patch adds the ftrace debugging functionality to the parisc kernel. It will currently only work with 64bit kernels, because the gcc options -pg and -ffunction-sections can't be enabled at the same time and -ffunction-sections is still needed to be able to link 32bit kernels. Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Kyle McMartin <kyle@mcmartin.ca>
-rw-r--r--arch/parisc/Kconfig3
-rw-r--r--arch/parisc/Makefile4
-rw-r--r--arch/parisc/include/asm/ftrace.h25
-rw-r--r--arch/parisc/kernel/Makefile14
-rw-r--r--arch/parisc/kernel/entry.S27
-rw-r--r--arch/parisc/kernel/ftrace.c185
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c5
-rw-r--r--arch/parisc/kernel/smp.c3
-rw-r--r--arch/parisc/kernel/time.c3
-rw-r--r--arch/parisc/kernel/traps.c2
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S2
11 files changed, 269 insertions, 4 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 4866e2f8d3bb..7fd696fd3aef 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -9,6 +9,9 @@ config PARISC
9 def_bool y 9 def_bool y
10 select HAVE_IDE 10 select HAVE_IDE
11 select HAVE_OPROFILE 11 select HAVE_OPROFILE
12 select HAVE_FUNCTION_TRACER if 64BIT
13 select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
14 select HAVE_FUNCTION_TRACE_MCOUNT_TEST if 64BIT
12 select RTC_CLASS 15 select RTC_CLASS
13 select RTC_DRV_PARISC 16 select RTC_DRV_PARISC
14 select INIT_ALL_POSSIBLE 17 select INIT_ALL_POSSIBLE
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
index 0d428278356d..da6f66901c92 100644
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -56,7 +56,9 @@ cflags-y += -mdisable-fpregs
56 56
57# Without this, "ld -r" results in .text sections that are too big 57# Without this, "ld -r" results in .text sections that are too big
58# (> 0x40000) for branches to reach stubs. 58# (> 0x40000) for branches to reach stubs.
59cflags-y += -ffunction-sections 59ifndef CONFIG_FUNCTION_TRACER
60 cflags-y += -ffunction-sections
61endif
60 62
61# select which processor to optimise for 63# select which processor to optimise for
62cflags-$(CONFIG_PA7100) += -march=1.1 -mschedule=7100 64cflags-$(CONFIG_PA7100) += -march=1.1 -mschedule=7100
diff --git a/arch/parisc/include/asm/ftrace.h b/arch/parisc/include/asm/ftrace.h
new file mode 100644
index 000000000000..2fa05dd6aeee
--- /dev/null
+++ b/arch/parisc/include/asm/ftrace.h
@@ -0,0 +1,25 @@
1#ifndef _ASM_PARISC_FTRACE_H
2#define _ASM_PARISC_FTRACE_H
3
4#ifndef __ASSEMBLY__
5extern void mcount(void);
6
7/*
8 * Stack of return addresses for functions of a thread.
9 * Used in struct thread_info
10 */
11struct ftrace_ret_stack {
12 unsigned long ret;
13 unsigned long func;
14 unsigned long long calltime;
15};
16
17/*
18 * Primary handler of a function return.
19 * It relays on ftrace_return_to_handler.
20 * Defined in entry.S
21 */
22extern void return_to_handler(void);
23#endif /* __ASSEMBLY__ */
24
25#endif /* _ASM_PARISC_FTRACE_H */
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile
index a7ba8cd9417f..67db0722e6ca 100644
--- a/arch/parisc/kernel/Makefile
+++ b/arch/parisc/kernel/Makefile
@@ -11,6 +11,18 @@ obj-y := cache.o pacache.o setup.o traps.o time.o irq.o \
11 process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \ 11 process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \
12 topology.o 12 topology.o
13 13
14ifdef CONFIG_FUNCTION_TRACER
15# Do not profile debug and lowlevel utilities
16CFLAGS_REMOVE_ftrace.o = -pg
17CFLAGS_REMOVE_cache.o = -pg
18CFLAGS_REMOVE_irq.o = -pg
19CFLAGS_REMOVE_pacache.o = -pg
20CFLAGS_REMOVE_perf.o = -pg
21CFLAGS_REMOVE_traps.o = -pg
22CFLAGS_REMOVE_unaligned.o = -pg
23CFLAGS_REMOVE_unwind.o = -pg
24endif
25
14obj-$(CONFIG_SMP) += smp.o 26obj-$(CONFIG_SMP) += smp.o
15obj-$(CONFIG_PA11) += pci-dma.o 27obj-$(CONFIG_PA11) += pci-dma.o
16obj-$(CONFIG_PCI) += pci.o 28obj-$(CONFIG_PCI) += pci.o
@@ -19,3 +31,5 @@ obj-$(CONFIG_64BIT) += binfmt_elf32.o sys_parisc32.o signal32.o
19obj-$(CONFIG_STACKTRACE)+= stacktrace.o 31obj-$(CONFIG_STACKTRACE)+= stacktrace.o
20# only supported for PCX-W/U in 64-bit mode at the moment 32# only supported for PCX-W/U in 64-bit mode at the moment
21obj-$(CONFIG_64BIT) += perf.o perf_asm.o 33obj-$(CONFIG_64BIT) += perf.o perf_asm.o
34obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
35obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 4e9dd15e076c..ae3e70cd1e14 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -2185,6 +2185,33 @@ syscall_do_resched:
2185ENDPROC(syscall_exit) 2185ENDPROC(syscall_exit)
2186 2186
2187 2187
2188#ifdef CONFIG_FUNCTION_TRACER
2189 .import ftrace_function_trampoline,code
2190ENTRY(_mcount)
2191 copy %r3, %arg2
2192 b ftrace_function_trampoline
2193 nop
2194ENDPROC(_mcount)
2195
2196ENTRY(return_to_handler)
2197 load32 return_trampoline, %rp
2198 copy %ret0, %arg0
2199 copy %ret1, %arg1
2200 b ftrace_return_to_handler
2201 nop
2202return_trampoline:
2203 copy %ret0, %rp
2204 copy %r23, %ret0
2205 copy %r24, %ret1
2206
2207.globl ftrace_stub
2208ftrace_stub:
2209 bv %r0(%rp)
2210 nop
2211ENDPROC(return_to_handler)
2212#endif /* CONFIG_FUNCTION_TRACER */
2213
2214
2188get_register: 2215get_register:
2189 /* 2216 /*
2190 * get_register is used by the non access tlb miss handlers to 2217 * get_register is used by the non access tlb miss handlers to
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c
new file mode 100644
index 000000000000..9877372ffdba
--- /dev/null
+++ b/arch/parisc/kernel/ftrace.c
@@ -0,0 +1,185 @@
1/*
2 * Code for tracing calls in Linux kernel.
3 * Copyright (C) 2009 Helge Deller <deller@gmx.de>
4 *
5 * based on code for x86 which is:
6 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
7 *
8 * future possible enhancements:
9 * - add CONFIG_DYNAMIC_FTRACE
10 * - add CONFIG_STACK_TRACER
11 */
12
13#include <linux/init.h>
14#include <linux/ftrace.h>
15
16#include <asm/sections.h>
17#include <asm/ftrace.h>
18
19
20
21#ifdef CONFIG_FUNCTION_GRAPH_TRACER
22
23/* Add a function return address to the trace stack on thread info.*/
24static int push_return_trace(unsigned long ret, unsigned long long time,
25 unsigned long func, int *depth)
26{
27 int index;
28
29 if (!current->ret_stack)
30 return -EBUSY;
31
32 /* The return trace stack is full */
33 if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
34 atomic_inc(&current->trace_overrun);
35 return -EBUSY;
36 }
37
38 index = ++current->curr_ret_stack;
39 barrier();
40 current->ret_stack[index].ret = ret;
41 current->ret_stack[index].func = func;
42 current->ret_stack[index].calltime = time;
43 *depth = index;
44
45 return 0;
46}
47
48/* Retrieve a function return address to the trace stack on thread info.*/
49static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
50{
51 int index;
52
53 index = current->curr_ret_stack;
54
55 if (unlikely(index < 0)) {
56 ftrace_graph_stop();
57 WARN_ON(1);
58 /* Might as well panic, otherwise we have no where to go */
59 *ret = (unsigned long)
60 dereference_function_descriptor(&panic);
61 return;
62 }
63
64 *ret = current->ret_stack[index].ret;
65 trace->func = current->ret_stack[index].func;
66 trace->calltime = current->ret_stack[index].calltime;
67 trace->overrun = atomic_read(&current->trace_overrun);
68 trace->depth = index;
69 barrier();
70 current->curr_ret_stack--;
71
72}
73
74/*
75 * Send the trace to the ring-buffer.
76 * @return the original return address.
77 */
78unsigned long ftrace_return_to_handler(unsigned long retval0,
79 unsigned long retval1)
80{
81 struct ftrace_graph_ret trace;
82 unsigned long ret;
83
84 pop_return_trace(&trace, &ret);
85 trace.rettime = cpu_clock(raw_smp_processor_id());
86 ftrace_graph_return(&trace);
87
88 if (unlikely(!ret)) {
89 ftrace_graph_stop();
90 WARN_ON(1);
91 /* Might as well panic. What else to do? */
92 ret = (unsigned long)
93 dereference_function_descriptor(&panic);
94 }
95
96 /* HACK: we hand over the old functions' return values
97 in %r23 and %r24. Assembly in entry.S will take care
98 and move those to their final registers %ret0 and %ret1 */
99 asm( "copy %0, %%r23 \n\t"
100 "copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );
101
102 return ret;
103}
104
105/*
106 * Hook the return address and push it in the stack of return addrs
107 * in current thread info.
108 */
109void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
110{
111 unsigned long old;
112 unsigned long long calltime;
113 struct ftrace_graph_ent trace;
114
115 if (unlikely(atomic_read(&current->tracing_graph_pause)))
116 return;
117
118 old = *parent;
119 *parent = (unsigned long)
120 dereference_function_descriptor(&return_to_handler);
121
122 if (unlikely(!__kernel_text_address(old))) {
123 ftrace_graph_stop();
124 *parent = old;
125 WARN_ON(1);
126 return;
127 }
128
129 calltime = cpu_clock(raw_smp_processor_id());
130
131 if (push_return_trace(old, calltime,
132 self_addr, &trace.depth) == -EBUSY) {
133 *parent = old;
134 return;
135 }
136
137 trace.func = self_addr;
138
139 /* Only trace if the calling function expects to */
140 if (!ftrace_graph_entry(&trace)) {
141 current->curr_ret_stack--;
142 *parent = old;
143 }
144}
145
146#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
147
148
149void ftrace_function_trampoline(unsigned long parent,
150 unsigned long self_addr,
151 unsigned long org_sp_gr3)
152{
153 extern ftrace_func_t ftrace_trace_function;
154
155 if (function_trace_stop)
156 return;
157
158 if (ftrace_trace_function != ftrace_stub) {
159 ftrace_trace_function(parent, self_addr);
160 return;
161 }
162#ifdef CONFIG_FUNCTION_GRAPH_TRACER
163 if (ftrace_graph_entry && ftrace_graph_return) {
164 unsigned long sp;
165 unsigned long *parent_rp;
166
167 asm volatile ("copy %%r30, %0" : "=r"(sp));
168 /* sanity check: is stack pointer which we got from
169 assembler function in entry.S in a reasonable
170 range compared to current stack pointer? */
171 if ((sp - org_sp_gr3) > 0x400)
172 return;
173
174 /* calculate pointer to %rp in stack */
175 parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
176 /* sanity check: parent_rp should hold parent */
177 if (*parent_rp != parent)
178 return;
179
180 prepare_ftrace_return(parent_rp, self_addr);
181 return;
182 }
183#endif
184}
185
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index 0eecfbbc59cd..df653663d3db 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -153,5 +153,10 @@ EXPORT_SYMBOL(node_data);
153EXPORT_SYMBOL(pfnnid_map); 153EXPORT_SYMBOL(pfnnid_map);
154#endif 154#endif
155 155
156#ifdef CONFIG_FUNCTION_TRACER
157extern void _mcount(void);
158EXPORT_SYMBOL(_mcount);
159#endif
160
156/* from pacache.S -- needed for copy_page */ 161/* from pacache.S -- needed for copy_page */
157EXPORT_SYMBOL(copy_user_page_asm); 162EXPORT_SYMBOL(copy_user_page_asm);
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 9995d7ed5819..8545f2e7a2c0 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -31,6 +31,7 @@
31#include <linux/err.h> 31#include <linux/err.h>
32#include <linux/delay.h> 32#include <linux/delay.h>
33#include <linux/bitops.h> 33#include <linux/bitops.h>
34#include <linux/ftrace.h>
34 35
35#include <asm/system.h> 36#include <asm/system.h>
36#include <asm/atomic.h> 37#include <asm/atomic.h>
@@ -120,7 +121,7 @@ halt_processor(void)
120} 121}
121 122
122 123
123irqreturn_t 124irqreturn_t __irq_entry
124ipi_interrupt(int irq, void *dev_id) 125ipi_interrupt(int irq, void *dev_id)
125{ 126{
126 int this_cpu = smp_processor_id(); 127 int this_cpu = smp_processor_id();
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 9d46c43a4152..badaad9ff139 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -24,6 +24,7 @@
24#include <linux/profile.h> 24#include <linux/profile.h>
25#include <linux/clocksource.h> 25#include <linux/clocksource.h>
26#include <linux/platform_device.h> 26#include <linux/platform_device.h>
27#include <linux/ftrace.h>
27 28
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
29#include <asm/io.h> 30#include <asm/io.h>
@@ -53,7 +54,7 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */
53 * held off for an arbitrarily long period of time by interrupts being 54 * held off for an arbitrarily long period of time by interrupts being
54 * disabled, so we may miss one or more ticks. 55 * disabled, so we may miss one or more ticks.
55 */ 56 */
56irqreturn_t timer_interrupt(int irq, void *dev_id) 57irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
57{ 58{
58 unsigned long now; 59 unsigned long now;
59 unsigned long next_tick; 60 unsigned long next_tick;
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index ba658d2086f7..7bf122a5f169 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -494,7 +494,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
494 panic(msg); 494 panic(msg);
495} 495}
496 496
497void handle_interruption(int code, struct pt_regs *regs) 497void notrace handle_interruption(int code, struct pt_regs *regs)
498{ 498{
499 unsigned long fault_address = 0; 499 unsigned long fault_address = 0;
500 unsigned long fault_space = 0; 500 unsigned long fault_space = 0;
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 1a3b6ccd3620..fd2cc4fd2b65 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -54,6 +54,8 @@ SECTIONS
54 TEXT_TEXT 54 TEXT_TEXT
55 SCHED_TEXT 55 SCHED_TEXT
56 LOCK_TEXT 56 LOCK_TEXT
57 KPROBES_TEXT
58 IRQENTRY_TEXT
57 *(.text.do_softirq) 59 *(.text.do_softirq)
58 *(.text.sys_exit) 60 *(.text.sys_exit)
59 *(.text.do_sigaltstack) 61 *(.text.do_sigaltstack)