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
select ARCH_MIGHT_HAVE_PC_PARPORT
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_FUNCTION_TRACER if 64BIT
select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select ARCH_WANT_FRAME_POINTERS
select RTC_CLASS
select RTC_DRV_GENERIC
......
......@@ -2,9 +2,13 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
config TRACE_IRQFLAGS_SUPPORT
def_bool y
config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
depends on DEBUG_KERNEL
default y
help
Mark the kernel read-only data as write-protected in the pagetables,
in order to catch accidental (and incorrect) writes to such const
......
......@@ -62,9 +62,7 @@ cflags-y += -mdisable-fpregs
# Without this, "ld -r" results in .text sections that are too big
# (> 0x40000) for branches to reach stubs.
ifndef CONFIG_FUNCTION_TRACER
cflags-y += -ffunction-sections
endif
cflags-y += -ffunction-sections
# Use long jumps instead of long branches (needed if your linker fails to
# link a too big vmlinux executable). Not enabled for building modules.
......
......@@ -4,23 +4,7 @@
#ifndef __ASSEMBLY__
extern void mcount(void);
/*
* 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);
#define MCOUNT_INSN_SIZE 4
extern unsigned long return_address(unsigned int);
......
......@@ -15,11 +15,7 @@ ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_cache.o = -pg
CFLAGS_REMOVE_irq.o = -pg
CFLAGS_REMOVE_pacache.o = -pg
CFLAGS_REMOVE_perf.o = -pg
CFLAGS_REMOVE_traps.o = -pg
CFLAGS_REMOVE_unaligned.o = -pg
CFLAGS_REMOVE_unwind.o = -pg
endif
......
......@@ -1970,43 +1970,98 @@ pt_regs_ok:
b intr_restore
copy %r25,%r16
.import schedule,code
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
ldo -16(%r30),%r29 /* Reference param save area */
#else
nop
#endif
b syscall_check_resched /* if resched, we start over again */
nop
ENDPROC(syscall_exit)
#ifdef CONFIG_FUNCTION_TRACER
.import ftrace_function_trampoline,code
ENTRY(_mcount)
copy %r3, %arg2
.align L1_CACHE_BYTES
.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
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
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)
load32 return_trampoline, %rp
copy %ret0, %arg0
copy %ret1, %arg1
b ftrace_return_to_handler
nop
return_trampoline:
copy %ret0, %rp
copy %r23, %ret0
copy %r24, %ret1
.proc
.callinfo caller,frame=FRAME_SIZE
.entry
.export parisc_return_to_handler,data
parisc_return_to_handler:
copy %r3,%r1
STREG %r0,-RP_OFFSET(%sp) /* store 0 as %rp */
copy %sp,%r3
STREGM %r1,FRAME_SIZE(%sp)
STREG %ret0,8(%r3)
STREG %ret1,16(%r3)
.globl ftrace_stub
ftrace_stub:
#ifdef CONFIG_64BIT
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)
nop
#endif
LDREGM -FRAME_SIZE(%sp),%r3
.exit
.procend
ENDPROC(return_to_handler)
#endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_IRQSTACKS
......
/*
* 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:
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
......@@ -13,104 +13,21 @@
#include <linux/init.h>
#include <linux/ftrace.h>
#include <asm/assembly.h>
#include <asm/sections.h>
#include <asm/ftrace.h>
#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
* 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 long calltime;
struct ftrace_graph_ent trace;
extern int parisc_return_to_handler;
if (unlikely(ftrace_graph_is_dead()))
return;
......@@ -119,64 +36,47 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
return;
old = *parent;
*parent = (unsigned long)
dereference_function_descriptor(&return_to_handler);
if (unlikely(!__kernel_text_address(old))) {
ftrace_graph_stop();
*parent = old;
WARN_ON(1);
return;
}
calltime = local_clock();
trace.func = self_addr;
trace.depth = current->curr_ret_stack + 1;
if (push_return_trace(old, calltime,
self_addr, &trace.depth) == -EBUSY) {
*parent = old;
/* Only trace if the calling function expects to */
if (!ftrace_graph_entry(&trace))
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 */
if (!ftrace_graph_entry(&trace)) {
current->curr_ret_stack--;
*parent = old;
}
/* activate parisc_return_to_handler() as return point */
*parent = (unsigned long) &parisc_return_to_handler;
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
void ftrace_function_trampoline(unsigned long parent,
void notrace ftrace_function_trampoline(unsigned long parent,
unsigned long self_addr,
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) {
ftrace_trace_function(parent, self_addr);
/* struct ftrace_ops *op, struct pt_regs *regs); */
ftrace_trace_function(parent, self_addr, NULL, NULL);
return;
}
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
if (ftrace_graph_entry && ftrace_graph_return) {
unsigned long sp;
if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
ftrace_graph_entry != ftrace_graph_entry_stub) {
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 */
parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
/* sanity check: parent_rp should hold parent */
if (*parent_rp != parent)
return;
prepare_ftrace_return(parent_rp, self_addr);
return;
}
......
......@@ -129,6 +129,15 @@ $pgt_fill_loop:
/* And the stack pointer too */
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
/* Set the smp rendezvous address into page zero.
** 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