sparc64: Add function graph tracer support.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -93,6 +93,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o
|
||||
|
||||
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
|
||||
obj-$(CONFIG_EARLYFB) += btext.o
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
|
@@ -91,3 +91,61 @@ int __init ftrace_dyn_arch_init(void *data)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
extern void ftrace_graph_call(void);
|
||||
|
||||
int ftrace_enable_ftrace_graph_caller(void)
|
||||
{
|
||||
unsigned long ip = (unsigned long)(&ftrace_graph_call);
|
||||
u32 old, new;
|
||||
|
||||
old = *(u32 *) &ftrace_graph_call;
|
||||
new = ftrace_call_replace(ip, (unsigned long) &ftrace_graph_caller);
|
||||
return ftrace_modify_code(ip, old, new);
|
||||
}
|
||||
|
||||
int ftrace_disable_ftrace_graph_caller(void)
|
||||
{
|
||||
unsigned long ip = (unsigned long)(&ftrace_graph_call);
|
||||
u32 old, new;
|
||||
|
||||
old = *(u32 *) &ftrace_graph_call;
|
||||
new = ftrace_call_replace(ip, (unsigned long) &ftrace_stub);
|
||||
|
||||
return ftrace_modify_code(ip, old, new);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
/*
|
||||
* Hook the return address and push it in the stack of return addrs
|
||||
* in current thread info.
|
||||
*/
|
||||
unsigned long prepare_ftrace_return(unsigned long parent,
|
||||
unsigned long self_addr,
|
||||
unsigned long frame_pointer)
|
||||
{
|
||||
unsigned long return_hooker = (unsigned long) &return_to_handler;
|
||||
struct ftrace_graph_ent trace;
|
||||
|
||||
if (unlikely(atomic_read(¤t->tracing_graph_pause)))
|
||||
return parent + 8UL;
|
||||
|
||||
if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
|
||||
frame_pointer) == -EBUSY)
|
||||
return parent + 8UL;
|
||||
|
||||
trace.func = self_addr;
|
||||
|
||||
/* Only trace if the calling function expects to */
|
||||
if (!ftrace_graph_entry(&trace)) {
|
||||
current->curr_ret_stack--;
|
||||
return parent + 8UL;
|
||||
}
|
||||
|
||||
return return_hooker;
|
||||
}
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
@@ -721,7 +722,7 @@ static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
|
||||
__asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
|
||||
}
|
||||
|
||||
void handler_irq(int irq, struct pt_regs *regs)
|
||||
void __irq_entry handler_irq(int irq, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long pstate, bucket_pa;
|
||||
struct pt_regs *old_regs;
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/kdebug.h>
|
||||
#include <asm/ptrace.h>
|
||||
@@ -108,7 +109,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void smp_kgdb_capture_client(int irq, struct pt_regs *regs)
|
||||
void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/pil.h>
|
||||
#include <asm/pcr.h>
|
||||
@@ -34,7 +35,7 @@ unsigned int picl_shift;
|
||||
* Therefore in such situations we defer the work by signalling
|
||||
* a lower level cpu IRQ.
|
||||
*/
|
||||
void deferred_pcr_work_irq(int irq, struct pt_regs *regs)
|
||||
void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <linux/profile.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/head.h>
|
||||
@@ -822,13 +823,13 @@ void arch_send_call_function_single_ipi(int cpu)
|
||||
&cpumask_of_cpu(cpu));
|
||||
}
|
||||
|
||||
void smp_call_function_client(int irq, struct pt_regs *regs)
|
||||
void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs)
|
||||
{
|
||||
clear_softint(1 << irq);
|
||||
generic_smp_call_function_interrupt();
|
||||
}
|
||||
|
||||
void smp_call_function_single_client(int irq, struct pt_regs *regs)
|
||||
void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs)
|
||||
{
|
||||
clear_softint(1 << irq);
|
||||
generic_smp_call_function_single_interrupt();
|
||||
@@ -964,7 +965,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
|
||||
void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct mm_struct *mm;
|
||||
unsigned long flags;
|
||||
@@ -1148,7 +1149,7 @@ void smp_release(void)
|
||||
*/
|
||||
extern void prom_world(int);
|
||||
|
||||
void smp_penguin_jailcell(int irq, struct pt_regs *regs)
|
||||
void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs)
|
||||
{
|
||||
clear_softint(1 << irq);
|
||||
|
||||
@@ -1364,7 +1365,7 @@ void smp_send_reschedule(int cpu)
|
||||
&cpumask_of_cpu(cpu));
|
||||
}
|
||||
|
||||
void smp_receive_signal_client(int irq, struct pt_regs *regs)
|
||||
void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
|
||||
{
|
||||
clear_softint(1 << irq);
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/timer.h>
|
||||
@@ -717,7 +718,7 @@ static struct clock_event_device sparc64_clockevent = {
|
||||
};
|
||||
static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
|
||||
|
||||
void timer_interrupt(int irq, struct pt_regs *regs)
|
||||
void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
unsigned long tick_mask = tick_ops->softint_mask;
|
||||
|
@@ -46,6 +46,7 @@ SECTIONS
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
IRQENTRY_TEXT
|
||||
*(.gnu.warning)
|
||||
} = 0
|
||||
_etext = .;
|
||||
|
Reference in New Issue
Block a user