Commit 60ea7bb0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc ftrace fixes from Helge Deller:
 "This is (most likely) the last pull request for v4.6 for the parisc
  architecture.

  It fixes the FTRACE feature for parisc, which is horribly broken since
   quite some time and doesn't even compile.  This patch just fixes the
  bare minimum (it actually removes more lines than it adds), so that
  the function tracer works again on 32- and 64bit kernels.

  I've queued up additional patches on top of this patch which e.g. add
  the syscall tracer, but those have to wait for the merge window for
  v4.7."

* 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Fix ftrace function tracer
parents 806fdcce 366dd4ea
...@@ -4,8 +4,8 @@ config PARISC ...@@ -4,8 +4,8 @@ config PARISC
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
select HAVE_IDE select HAVE_IDE
select HAVE_OPROFILE select HAVE_OPROFILE
select HAVE_FUNCTION_TRACER if 64BIT select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER if 64BIT select HAVE_FUNCTION_GRAPH_TRACER
select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_FRAME_POINTERS
select RTC_CLASS select RTC_CLASS
select RTC_DRV_GENERIC select RTC_DRV_GENERIC
......
...@@ -2,9 +2,13 @@ menu "Kernel hacking" ...@@ -2,9 +2,13 @@ menu "Kernel hacking"
source "lib/Kconfig.debug" source "lib/Kconfig.debug"
config TRACE_IRQFLAGS_SUPPORT
def_bool y
config DEBUG_RODATA config DEBUG_RODATA
bool "Write protect kernel read-only data structures" bool "Write protect kernel read-only data structures"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
default y
help help
Mark the kernel read-only data as write-protected in the pagetables, Mark the kernel read-only data as write-protected in the pagetables,
in order to catch accidental (and incorrect) writes to such const in order to catch accidental (and incorrect) writes to such const
......
...@@ -62,9 +62,7 @@ cflags-y += -mdisable-fpregs ...@@ -62,9 +62,7 @@ cflags-y += -mdisable-fpregs
# Without this, "ld -r" results in .text sections that are too big # Without this, "ld -r" results in .text sections that are too big
# (> 0x40000) for branches to reach stubs. # (> 0x40000) for branches to reach stubs.
ifndef CONFIG_FUNCTION_TRACER cflags-y += -ffunction-sections
cflags-y += -ffunction-sections
endif
# Use long jumps instead of long branches (needed if your linker fails to # Use long jumps instead of long branches (needed if your linker fails to
# link a too big vmlinux executable). Not enabled for building modules. # link a too big vmlinux executable). Not enabled for building modules.
......
...@@ -4,23 +4,7 @@ ...@@ -4,23 +4,7 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void mcount(void); extern void mcount(void);
/* #define MCOUNT_INSN_SIZE 4
* Stack of return addresses for functions of a thread.
* Used in struct thread_info
*/
struct ftrace_ret_stack {
unsigned long ret;
unsigned long func;
unsigned long long calltime;
};
/*
* Primary handler of a function return.
* It relays on ftrace_return_to_handler.
* Defined in entry.S
*/
extern void return_to_handler(void);
extern unsigned long return_address(unsigned int); extern unsigned long return_address(unsigned int);
......
...@@ -15,11 +15,7 @@ ifdef CONFIG_FUNCTION_TRACER ...@@ -15,11 +15,7 @@ ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities # Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_cache.o = -pg CFLAGS_REMOVE_cache.o = -pg
CFLAGS_REMOVE_irq.o = -pg
CFLAGS_REMOVE_pacache.o = -pg
CFLAGS_REMOVE_perf.o = -pg CFLAGS_REMOVE_perf.o = -pg
CFLAGS_REMOVE_traps.o = -pg
CFLAGS_REMOVE_unaligned.o = -pg
CFLAGS_REMOVE_unwind.o = -pg CFLAGS_REMOVE_unwind.o = -pg
endif endif
......
...@@ -1970,43 +1970,98 @@ pt_regs_ok: ...@@ -1970,43 +1970,98 @@ pt_regs_ok:
b intr_restore b intr_restore
copy %r25,%r16 copy %r25,%r16
.import schedule,code
syscall_do_resched: syscall_do_resched:
BL schedule,%r2 load32 syscall_check_resched,%r2 /* if resched, we start over again */
load32 schedule,%r19
bv %r0(%r19) /* jumps to schedule() */
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */ ldo -16(%r30),%r29 /* Reference param save area */
#else #else
nop nop
#endif #endif
b syscall_check_resched /* if resched, we start over again */
nop
ENDPROC(syscall_exit) ENDPROC(syscall_exit)
#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_FUNCTION_TRACER
.import ftrace_function_trampoline,code .import ftrace_function_trampoline,code
ENTRY(_mcount) .align L1_CACHE_BYTES
copy %r3, %arg2 .globl mcount
.type mcount, @function
ENTRY(mcount)
_mcount:
.export _mcount,data
.proc
.callinfo caller,frame=0
.entry
/*
* The 64bit mcount() function pointer needs 4 dwords, of which the
* first two are free. We optimize it here and put 2 instructions for
* calling mcount(), and 2 instructions for ftrace_stub(). That way we
* have all on one L1 cacheline.
*/
b ftrace_function_trampoline b ftrace_function_trampoline
copy %r3, %arg2 /* caller original %sp */
ftrace_stub:
.globl ftrace_stub
.type ftrace_stub, @function
#ifdef CONFIG_64BIT
bve (%rp)
#else
bv %r0(%rp)
#endif
nop nop
ENDPROC(_mcount) #ifdef CONFIG_64BIT
.dword mcount
.dword 0 /* code in head.S puts value of global gp here */
#endif
.exit
.procend
ENDPROC(mcount)
.align 8
.globl return_to_handler
.type return_to_handler, @function
ENTRY(return_to_handler) ENTRY(return_to_handler)
load32 return_trampoline, %rp .proc
copy %ret0, %arg0 .callinfo caller,frame=FRAME_SIZE
copy %ret1, %arg1 .entry
b ftrace_return_to_handler .export parisc_return_to_handler,data
nop parisc_return_to_handler:
return_trampoline: copy %r3,%r1
copy %ret0, %rp STREG %r0,-RP_OFFSET(%sp) /* store 0 as %rp */
copy %r23, %ret0 copy %sp,%r3
copy %r24, %ret1 STREGM %r1,FRAME_SIZE(%sp)
STREG %ret0,8(%r3)
STREG %ret1,16(%r3)
.globl ftrace_stub #ifdef CONFIG_64BIT
ftrace_stub: loadgp
#endif
/* call ftrace_return_to_handler(0) */
#ifdef CONFIG_64BIT
ldo -16(%sp),%ret1 /* Reference param save area */
#endif
BL ftrace_return_to_handler,%r2
ldi 0,%r26
copy %ret0,%rp
/* restore original return values */
LDREG 8(%r3),%ret0
LDREG 16(%r3),%ret1
/* return from function */
#ifdef CONFIG_64BIT
bve (%rp)
#else
bv %r0(%rp) bv %r0(%rp)
nop #endif
LDREGM -FRAME_SIZE(%sp),%r3
.exit
.procend
ENDPROC(return_to_handler) ENDPROC(return_to_handler)
#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_IRQSTACKS #ifdef CONFIG_IRQSTACKS
......
/* /*
* Code for tracing calls in Linux kernel. * Code for tracing calls in Linux kernel.
* Copyright (C) 2009 Helge Deller <deller@gmx.de> * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
* *
* based on code for x86 which is: * based on code for x86 which is:
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
...@@ -13,104 +13,21 @@ ...@@ -13,104 +13,21 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <asm/assembly.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/ftrace.h> #include <asm/ftrace.h>
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
/* Add a function return address to the trace stack on thread info.*/
static int push_return_trace(unsigned long ret, unsigned long long time,
unsigned long func, int *depth)
{
int index;
if (!current->ret_stack)
return -EBUSY;
/* The return trace stack is full */
if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
atomic_inc(&current->trace_overrun);
return -EBUSY;
}
index = ++current->curr_ret_stack;
barrier();
current->ret_stack[index].ret = ret;
current->ret_stack[index].func = func;
current->ret_stack[index].calltime = time;
*depth = index;
return 0;
}
/* Retrieve a function return address to the trace stack on thread info.*/
static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
{
int index;
index = current->curr_ret_stack;
if (unlikely(index < 0)) {
ftrace_graph_stop();
WARN_ON(1);
/* Might as well panic, otherwise we have no where to go */
*ret = (unsigned long)
dereference_function_descriptor(&panic);
return;
}
*ret = current->ret_stack[index].ret;
trace->func = current->ret_stack[index].func;
trace->calltime = current->ret_stack[index].calltime;
trace->overrun = atomic_read(&current->trace_overrun);
trace->depth = index;
barrier();
current->curr_ret_stack--;
}
/*
* Send the trace to the ring-buffer.
* @return the original return address.
*/
unsigned long ftrace_return_to_handler(unsigned long retval0,
unsigned long retval1)
{
struct ftrace_graph_ret trace;
unsigned long ret;
pop_return_trace(&trace, &ret);
trace.rettime = local_clock();
ftrace_graph_return(&trace);
if (unlikely(!ret)) {
ftrace_graph_stop();
WARN_ON(1);
/* Might as well panic. What else to do? */
ret = (unsigned long)
dereference_function_descriptor(&panic);
}
/* HACK: we hand over the old functions' return values
in %r23 and %r24. Assembly in entry.S will take care
and move those to their final registers %ret0 and %ret1 */
asm( "copy %0, %%r23 \n\t"
"copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );
return ret;
}
/* /*
* Hook the return address and push it in the stack of return addrs * Hook the return address and push it in the stack of return addrs
* in current thread info. * in current thread info.
*/ */
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) static void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
{ {
unsigned long old; unsigned long old;
unsigned long long calltime;
struct ftrace_graph_ent trace; struct ftrace_graph_ent trace;
extern int parisc_return_to_handler;
if (unlikely(ftrace_graph_is_dead())) if (unlikely(ftrace_graph_is_dead()))
return; return;
...@@ -119,60 +36,43 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) ...@@ -119,60 +36,43 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return; return;
old = *parent; old = *parent;
*parent = (unsigned long)
dereference_function_descriptor(&return_to_handler);
if (unlikely(!__kernel_text_address(old))) { trace.func = self_addr;
ftrace_graph_stop(); trace.depth = current->curr_ret_stack + 1;
*parent = old;
WARN_ON(1);
return;
}
calltime = local_clock();
if (push_return_trace(old, calltime, /* Only trace if the calling function expects to */
self_addr, &trace.depth) == -EBUSY) { if (!ftrace_graph_entry(&trace))
*parent = old;
return; return;
}
trace.func = self_addr; if (ftrace_push_return_trace(old, self_addr, &trace.depth,
0 ) == -EBUSY)
return;
/* Only trace if the calling function expects to */ /* activate parisc_return_to_handler() as return point */
if (!ftrace_graph_entry(&trace)) { *parent = (unsigned long) &parisc_return_to_handler;
current->curr_ret_stack--;
*parent = old;
}
} }
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
void notrace ftrace_function_trampoline(unsigned long parent,
void ftrace_function_trampoline(unsigned long parent,
unsigned long self_addr, unsigned long self_addr,
unsigned long org_sp_gr3) unsigned long org_sp_gr3)
{ {
extern ftrace_func_t ftrace_trace_function; extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
if (ftrace_trace_function != ftrace_stub) { if (ftrace_trace_function != ftrace_stub) {
ftrace_trace_function(parent, self_addr); /* struct ftrace_ops *op, struct pt_regs *regs); */
ftrace_trace_function(parent, self_addr, NULL, NULL);
return; return;
} }
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
if (ftrace_graph_entry && ftrace_graph_return) { if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
unsigned long sp; ftrace_graph_entry != ftrace_graph_entry_stub) {
unsigned long *parent_rp; unsigned long *parent_rp;
asm volatile ("copy %%r30, %0" : "=r"(sp));
/* sanity check: is stack pointer which we got from
assembler function in entry.S in a reasonable
range compared to current stack pointer? */
if ((sp - org_sp_gr3) > 0x400)
return;
/* calculate pointer to %rp in stack */ /* calculate pointer to %rp in stack */
parent_rp = (unsigned long *) org_sp_gr3 - 0x10; parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
/* sanity check: parent_rp should hold parent */ /* sanity check: parent_rp should hold parent */
if (*parent_rp != parent) if (*parent_rp != parent)
return; return;
......
...@@ -129,6 +129,15 @@ $pgt_fill_loop: ...@@ -129,6 +129,15 @@ $pgt_fill_loop:
/* And the stack pointer too */ /* And the stack pointer too */
ldo THREAD_SZ_ALGN(%r6),%sp ldo THREAD_SZ_ALGN(%r6),%sp
#if defined(CONFIG_64BIT) && defined(CONFIG_FUNCTION_TRACER)
.import _mcount,data
/* initialize mcount FPTR */
/* Get the global data pointer */
loadgp
load32 PA(_mcount), %r10
std %dp,0x18(%r10)
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Set the smp rendezvous address into page zero. /* Set the smp rendezvous address into page zero.
** It would be safer to do this in init_smp_config() but ** It would be safer to do this in init_smp_config() but
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment