2008-05-14 23:49:44 -04:00
/*
* Code for replacing ftrace calls with jumps .
*
* Copyright ( C ) 2007 - 2008 Steven Rostedt < srostedt @ redhat . com >
*
* Thanks goes out to P . A . Semi , Inc for supplying me with a PPC64 box .
*
2009-02-09 21:10:27 -08:00
* Added function graph tracer code , taken from x86 that was written
* by Frederic Weisbecker , and ported to PPC by Steven Rostedt .
*
2008-05-14 23:49:44 -04:00
*/
2014-06-17 16:15:36 +10:00
# define pr_fmt(fmt) "ftrace-powerpc: " fmt
2008-05-14 23:49:44 -04:00
# include <linux/spinlock.h>
# include <linux/hardirq.h>
2008-11-14 16:21:20 -08:00
# include <linux/uaccess.h>
2008-11-14 20:47:03 -08:00
# include <linux/module.h>
2008-05-14 23:49:44 -04:00
# include <linux/ftrace.h>
# include <linux/percpu.h>
# include <linux/init.h>
# include <linux/list.h>
# include <asm/cacheflush.h>
2008-11-14 20:47:03 -08:00
# include <asm/code-patching.h>
2008-06-21 23:47:27 +05:30
# include <asm/ftrace.h>
2011-02-02 17:27:24 +00:00
# include <asm/syscall.h>
2008-05-14 23:49:44 -04:00
2009-02-09 21:10:27 -08:00
# ifdef CONFIG_DYNAMIC_FTRACE
2009-02-13 06:31:39 -08:00
static unsigned int
2009-02-10 22:19:54 -08:00
ftrace_call_replace ( unsigned long ip , unsigned long addr , int link )
2008-05-14 23:49:44 -04:00
{
2009-02-13 06:31:39 -08:00
unsigned int op ;
2008-05-14 23:49:44 -04:00
2009-05-28 19:33:34 +00:00
addr = ppc_function_entry ( ( void * ) addr ) ;
2008-05-14 23:49:44 -04:00
2009-02-10 22:19:54 -08:00
/* if (link) set op to 'bl' else 'b' */
2009-02-13 06:45:27 -08:00
op = create_branch ( ( unsigned int * ) ip , addr , link ? 1 : 0 ) ;
2008-05-14 23:49:44 -04:00
2009-02-13 06:31:39 -08:00
return op ;
2008-05-14 23:49:44 -04:00
}
2008-11-14 16:21:19 -08:00
static int
2009-02-13 06:31:39 -08:00
ftrace_modify_code ( unsigned long ip , unsigned int old , unsigned int new )
2008-05-14 23:49:44 -04:00
{
2009-02-13 06:31:39 -08:00
unsigned int replaced ;
2008-05-14 23:49:44 -04:00
/*
* Note : Due to modules and __init , code can
* disappear and change , we need to protect against faulting
2008-11-14 16:21:20 -08:00
* as well as code changing . We do this by using the
* probe_kernel_ * functions .
2008-05-14 23:49:44 -04:00
*
* No real locking needed , this code is run through
2008-11-14 16:21:20 -08:00
* kstop_machine , or before SMP starts .
2008-05-14 23:49:44 -04:00
*/
2008-11-14 16:21:20 -08:00
/* read the text we want to modify */
2009-02-13 06:31:39 -08:00
if ( probe_kernel_read ( & replaced , ( void * ) ip , MCOUNT_INSN_SIZE ) )
2008-11-14 16:21:20 -08:00
return - EFAULT ;
/* Make sure it is what we expect it to be */
2009-02-13 06:31:39 -08:00
if ( replaced ! = old )
2008-11-14 16:21:20 -08:00
return - EINVAL ;
/* replace the text with the new text */
2012-04-26 08:31:19 +00:00
if ( patch_instruction ( ( unsigned int * ) ip , new ) )
2008-11-14 16:21:20 -08:00
return - EPERM ;
return 0 ;
2008-05-14 23:49:44 -04:00
}
2008-11-14 20:47:03 -08:00
/*
* Helper functions that are the same for both PPC64 and PPC32 .
*/
2008-11-14 16:21:19 -08:00
static int test_24bit_addr ( unsigned long ip , unsigned long addr )
{
2014-02-26 10:23:01 +08:00
addr = ppc_function_entry ( ( void * ) addr ) ;
2008-11-14 16:21:19 -08:00
2008-11-25 14:06:19 -08:00
/* use the create_branch to verify that this offset can be branched */
return create_branch ( ( unsigned int * ) ip , addr , 0 ) ;
2008-11-14 16:21:19 -08:00
}
2009-02-05 21:33:09 -08:00
# ifdef CONFIG_MODULES
2008-11-14 20:47:03 -08:00
static int is_bl_op ( unsigned int op )
{
return ( op & 0xfc000003 ) = = 0x48000001 ;
}
static unsigned long find_bl_target ( unsigned long ip , unsigned int op )
{
static int offset ;
offset = ( op & 0x03fffffc ) ;
/* make it signed */
if ( offset & 0x02000000 )
offset | = 0xfe000000 ;
return ip + ( long ) offset ;
}
# ifdef CONFIG_PPC64
static int
__ftrace_make_nop ( struct module * mod ,
struct dyn_ftrace * rec , unsigned long addr )
{
2008-11-25 06:39:18 -08:00
unsigned int op ;
2014-06-17 16:15:35 +10:00
unsigned long entry , ptr ;
2008-11-14 20:47:03 -08:00
unsigned long ip = rec - > ip ;
2014-04-04 16:52:58 +11:00
void * tramp ;
2008-11-14 20:47:03 -08:00
/* read where this goes */
2008-11-25 06:39:18 -08:00
if ( probe_kernel_read ( & op , ( void * ) ip , sizeof ( int ) ) )
2008-11-14 20:47:03 -08:00
return - EFAULT ;
/* Make sure that that this is still a 24bit jump */
2008-11-25 06:39:18 -08:00
if ( ! is_bl_op ( op ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Not expected bl: opcode is %x \n " , op ) ;
2008-11-14 20:47:03 -08:00
return - EINVAL ;
}
/* lets find where the pointer goes */
2014-04-04 16:52:58 +11:00
tramp = ( void * ) find_bl_target ( ip , op ) ;
2008-11-14 20:47:03 -08:00
2014-04-04 16:52:58 +11:00
pr_devel ( " ip:%lx jumps to %p " , ip , tramp ) ;
2008-11-14 20:47:03 -08:00
2014-04-04 16:52:58 +11:00
if ( ! is_module_trampoline ( tramp ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Not a trampoline \n " ) ;
2008-11-25 06:39:18 -08:00
return - EINVAL ;
}
2008-11-14 20:47:03 -08:00
2014-04-04 16:52:58 +11:00
if ( module_trampoline_target ( mod , tramp , & ptr ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Failed to get trampoline target \n " ) ;
2008-11-14 20:47:03 -08:00
return - EFAULT ;
}
2014-04-04 16:52:58 +11:00
pr_devel ( " trampoline target %lx " , ptr ) ;
2008-11-14 20:47:03 -08:00
2014-06-17 16:15:35 +10:00
entry = ppc_global_function_entry ( ( void * ) addr ) ;
2008-11-14 20:47:03 -08:00
/* This should match what was called */
2014-06-17 16:15:35 +10:00
if ( ptr ! = entry ) {
2014-06-17 16:15:36 +10:00
pr_err ( " addr %lx does not match expected %lx \n " , ptr , entry ) ;
2008-11-14 20:47:03 -08:00
return - EINVAL ;
}
/*
2014-04-04 16:52:58 +11:00
* Our original call site looks like :
*
* bl < tramp >
* ld r2 , XX ( r1 )
*
* Milton Miller pointed out that we can not simply nop the branch .
* If a task was preempted when calling a trace function , the nops
* will remove the way to restore the TOC in r2 and the r2 TOC will
* get corrupted .
*
* Use a b + 8 to jump over the load .
2008-11-14 20:47:03 -08:00
*/
2008-11-25 06:39:18 -08:00
op = 0x48000008 ; /* b +8 */
2008-11-14 20:47:03 -08:00
2012-04-26 08:31:19 +00:00
if ( patch_instruction ( ( unsigned int * ) ip , op ) )
2008-11-14 20:47:03 -08:00
return - EPERM ;
return 0 ;
}
# else /* !PPC64 */
static int
__ftrace_make_nop ( struct module * mod ,
struct dyn_ftrace * rec , unsigned long addr )
{
2008-11-25 06:39:18 -08:00
unsigned int op ;
unsigned int jmp [ 4 ] ;
2008-11-15 02:39:05 -05:00
unsigned long ip = rec - > ip ;
unsigned long tramp ;
2008-11-25 06:39:18 -08:00
if ( probe_kernel_read ( & op , ( void * ) ip , MCOUNT_INSN_SIZE ) )
2008-11-15 02:39:05 -05:00
return - EFAULT ;
/* Make sure that that this is still a 24bit jump */
2008-11-25 06:39:18 -08:00
if ( ! is_bl_op ( op ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Not expected bl: opcode is %x \n " , op ) ;
2008-11-15 02:39:05 -05:00
return - EINVAL ;
}
/* lets find where the pointer goes */
2008-11-25 06:39:18 -08:00
tramp = find_bl_target ( ip , op ) ;
2008-11-15 02:39:05 -05:00
/*
* On PPC32 the trampoline looks like :
2012-06-21 05:27:14 +00:00
* 0x3d , 0x80 , 0x00 , 0x00 lis r12 , sym @ ha
* 0x39 , 0x8c , 0x00 , 0x00 addi r12 , r12 , sym @ l
* 0x7d , 0x89 , 0x03 , 0xa6 mtctr r12
2008-11-25 06:39:18 -08:00
* 0x4e , 0x80 , 0x04 , 0x20 bctr
2008-11-15 02:39:05 -05:00
*/
2009-05-13 20:30:24 +00:00
pr_devel ( " ip:%lx jumps to %lx " , ip , tramp ) ;
2008-11-15 02:39:05 -05:00
/* Find where the trampoline jumps to */
2008-11-25 06:39:18 -08:00
if ( probe_kernel_read ( jmp , ( void * ) tramp , sizeof ( jmp ) ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Failed to read %lx \n " , tramp ) ;
2008-11-15 02:39:05 -05:00
return - EFAULT ;
}
2009-05-13 20:30:24 +00:00
pr_devel ( " %08x %08x " , jmp [ 0 ] , jmp [ 1 ] ) ;
2008-11-25 06:39:18 -08:00
/* verify that this is what we expect it to be */
2012-06-21 05:27:14 +00:00
if ( ( ( jmp [ 0 ] & 0xffff0000 ) ! = 0x3d800000 ) | |
( ( jmp [ 1 ] & 0xffff0000 ) ! = 0x398c0000 ) | |
( jmp [ 2 ] ! = 0x7d8903a6 ) | |
2008-11-25 06:39:18 -08:00
( jmp [ 3 ] ! = 0x4e800420 ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Not a trampoline \n " ) ;
2008-11-25 06:39:18 -08:00
return - EINVAL ;
}
2008-11-15 02:39:05 -05:00
2008-11-25 06:39:18 -08:00
tramp = ( jmp [ 1 ] & 0xffff ) |
( ( jmp [ 0 ] & 0xffff ) < < 16 ) ;
2008-11-15 02:39:05 -05:00
if ( tramp & 0x8000 )
tramp - = 0x10000 ;
2009-05-13 20:30:24 +00:00
pr_devel ( " %lx " , tramp ) ;
2008-11-15 02:39:05 -05:00
if ( tramp ! = addr ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Trampoline location %08lx does not match addr \n " ,
2008-11-15 02:39:05 -05:00
tramp ) ;
return - EINVAL ;
}
2009-02-10 20:10:44 +00:00
op = PPC_INST_NOP ;
2008-11-15 02:39:05 -05:00
2012-04-26 08:31:19 +00:00
if ( patch_instruction ( ( unsigned int * ) ip , op ) )
2008-11-15 02:39:05 -05:00
return - EPERM ;
2008-11-14 20:47:03 -08:00
return 0 ;
}
# endif /* PPC64 */
2009-02-05 21:33:09 -08:00
# endif /* CONFIG_MODULES */
2008-11-14 20:47:03 -08:00
2008-11-14 16:21:19 -08:00
int ftrace_make_nop ( struct module * mod ,
struct dyn_ftrace * rec , unsigned long addr )
{
2008-11-14 20:47:03 -08:00
unsigned long ip = rec - > ip ;
2009-02-13 06:31:39 -08:00
unsigned int old , new ;
2008-11-14 16:21:19 -08:00
/*
* If the calling address is more that 24 bits away ,
* then we had to use a trampoline to make the call .
* Otherwise just update the call site .
*/
2008-11-14 20:47:03 -08:00
if ( test_24bit_addr ( ip , addr ) ) {
2008-11-14 16:21:19 -08:00
/* within range */
2009-02-10 22:19:54 -08:00
old = ftrace_call_replace ( ip , addr , 1 ) ;
2009-05-28 19:33:36 +00:00
new = PPC_INST_NOP ;
2008-11-14 20:47:03 -08:00
return ftrace_modify_code ( ip , old , new ) ;
}
2009-02-05 21:33:09 -08:00
# ifdef CONFIG_MODULES
2008-11-14 20:47:03 -08:00
/*
* Out of range jumps are called from modules .
* We should either already have a pointer to the module
* or it has been passed in .
*/
if ( ! rec - > arch . mod ) {
if ( ! mod ) {
2014-06-17 16:15:36 +10:00
pr_err ( " No module loaded addr=%lx \n " , addr ) ;
2008-11-14 20:47:03 -08:00
return - EFAULT ;
}
rec - > arch . mod = mod ;
} else if ( mod ) {
if ( mod ! = rec - > arch . mod ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Record mod %p not equal to passed in mod %p \n " ,
2008-11-14 20:47:03 -08:00
rec - > arch . mod , mod ) ;
return - EINVAL ;
}
/* nothing to do if mod == rec->arch.mod */
} else
mod = rec - > arch . mod ;
return __ftrace_make_nop ( mod , rec , addr ) ;
2009-02-05 21:33:09 -08:00
# else
/* We should not get here without modules */
return - EINVAL ;
# endif /* CONFIG_MODULES */
2008-11-14 20:47:03 -08:00
}
2009-02-05 21:33:09 -08:00
# ifdef CONFIG_MODULES
2008-11-14 20:47:03 -08:00
# ifdef CONFIG_PPC64
static int
__ftrace_make_call ( struct dyn_ftrace * rec , unsigned long addr )
{
2008-11-25 06:39:18 -08:00
unsigned int op [ 2 ] ;
2014-04-04 16:54:04 +11:00
void * ip = ( void * ) rec - > ip ;
2008-11-14 20:47:03 -08:00
/* read where this goes */
2014-04-04 16:54:04 +11:00
if ( probe_kernel_read ( op , ip , sizeof ( op ) ) )
2008-11-14 20:47:03 -08:00
return - EFAULT ;
/*
2014-04-04 16:54:04 +11:00
* We expect to see :
*
* b + 8
* ld r2 , XX ( r1 )
*
* The load offset is different depending on the ABI . For simplicity
* just mask it out when doing the compare .
2008-11-14 20:47:03 -08:00
*/
2014-06-17 16:15:33 +10:00
if ( ( op [ 0 ] ! = 0x48000008 ) | | ( ( op [ 1 ] & 0xffff0000 ) ! = 0xe8410000 ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Unexpected call sequence: %x %x \n " , op [ 0 ] , op [ 1 ] ) ;
2008-11-14 20:47:03 -08:00
return - EINVAL ;
}
/* If we never set up a trampoline to ftrace_caller, then bail */
if ( ! rec - > arch . mod - > arch . tramp ) {
2014-06-17 16:15:36 +10:00
pr_err ( " No ftrace trampoline \n " ) ;
2008-11-14 20:47:03 -08:00
return - EINVAL ;
}
2014-04-04 16:54:04 +11:00
/* Ensure branch is within 24 bits */
2014-06-17 16:15:34 +10:00
if ( ! create_branch ( ip , rec - > arch . mod - > arch . tramp , BRANCH_SET_LINK ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Branch out of range \n " ) ;
2008-11-14 20:47:03 -08:00
return - EINVAL ;
2008-11-14 16:21:19 -08:00
}
2014-04-04 16:54:04 +11:00
if ( patch_branch ( ip , rec - > arch . mod - > arch . tramp , BRANCH_SET_LINK ) ) {
2014-06-17 16:15:36 +10:00
pr_err ( " REL24 out of range! \n " ) ;
2014-04-04 16:54:04 +11:00
return - EINVAL ;
}
2008-11-25 10:22:48 -08:00
2008-11-14 16:21:19 -08:00
return 0 ;
}
2008-11-14 20:47:03 -08:00
# else
static int
__ftrace_make_call ( struct dyn_ftrace * rec , unsigned long addr )
{
2008-11-25 06:39:18 -08:00
unsigned int op ;
2008-11-15 02:39:05 -05:00
unsigned long ip = rec - > ip ;
/* read where this goes */
2008-11-25 06:39:18 -08:00
if ( probe_kernel_read ( & op , ( void * ) ip , MCOUNT_INSN_SIZE ) )
2008-11-15 02:39:05 -05:00
return - EFAULT ;
/* It should be pointing to a nop */
2009-02-10 20:10:44 +00:00
if ( op ! = PPC_INST_NOP ) {
2014-06-17 16:15:36 +10:00
pr_err ( " Expected NOP but have %x \n " , op ) ;
2008-11-15 02:39:05 -05:00
return - EINVAL ;
}
/* If we never set up a trampoline to ftrace_caller, then bail */
if ( ! rec - > arch . mod - > arch . tramp ) {
2014-06-17 16:15:36 +10:00
pr_err ( " No ftrace trampoline \n " ) ;
2008-11-15 02:39:05 -05:00
return - EINVAL ;
}
2008-11-25 14:06:19 -08:00
/* create the branch to the trampoline */
op = create_branch ( ( unsigned int * ) ip ,
rec - > arch . mod - > arch . tramp , BRANCH_SET_LINK ) ;
if ( ! op ) {
2014-06-17 16:15:36 +10:00
pr_err ( " REL24 out of range! \n " ) ;
2008-11-15 02:39:05 -05:00
return - EINVAL ;
}
2009-05-13 20:30:24 +00:00
pr_devel ( " write to %lx \n " , rec - > ip ) ;
2008-11-15 02:39:05 -05:00
2012-04-26 08:31:19 +00:00
if ( patch_instruction ( ( unsigned int * ) ip , op ) )
2008-11-15 02:39:05 -05:00
return - EPERM ;
2008-11-14 20:47:03 -08:00
return 0 ;
}
# endif /* CONFIG_PPC64 */
2009-02-05 21:33:09 -08:00
# endif /* CONFIG_MODULES */
2008-11-14 16:21:19 -08:00
int ftrace_make_call ( struct dyn_ftrace * rec , unsigned long addr )
{
2008-11-14 20:47:03 -08:00
unsigned long ip = rec - > ip ;
2009-02-13 06:31:39 -08:00
unsigned int old , new ;
2008-11-14 16:21:19 -08:00
/*
* If the calling address is more that 24 bits away ,
* then we had to use a trampoline to make the call .
* Otherwise just update the call site .
*/
2008-11-14 20:47:03 -08:00
if ( test_24bit_addr ( ip , addr ) ) {
2008-11-14 16:21:19 -08:00
/* within range */
2009-05-28 19:33:36 +00:00
old = PPC_INST_NOP ;
2009-02-10 22:19:54 -08:00
new = ftrace_call_replace ( ip , addr , 1 ) ;
2008-11-14 20:47:03 -08:00
return ftrace_modify_code ( ip , old , new ) ;
2008-11-14 16:21:19 -08:00
}
2009-02-05 21:33:09 -08:00
# ifdef CONFIG_MODULES
2008-11-14 20:47:03 -08:00
/*
* Out of range jumps are called from modules .
* Being that we are converting from nop , it had better
* already have a module defined .
*/
if ( ! rec - > arch . mod ) {
2014-06-17 16:15:36 +10:00
pr_err ( " No module loaded \n " ) ;
2008-11-14 20:47:03 -08:00
return - EINVAL ;
}
return __ftrace_make_call ( rec , addr ) ;
2009-02-05 21:33:09 -08:00
# else
/* We should not get here without modules */
return - EINVAL ;
# endif /* CONFIG_MODULES */
2008-11-14 16:21:19 -08:00
}
2008-10-23 09:33:08 -04:00
int ftrace_update_ftrace_func ( ftrace_func_t func )
2008-05-14 23:49:44 -04:00
{
unsigned long ip = ( unsigned long ) ( & ftrace_call ) ;
2009-02-13 06:31:39 -08:00
unsigned int old , new ;
2008-05-14 23:49:44 -04:00
int ret ;
2009-02-13 06:31:39 -08:00
old = * ( unsigned int * ) & ftrace_call ;
2009-02-10 22:19:54 -08:00
new = ftrace_call_replace ( ip , ( unsigned long ) func , 1 ) ;
2008-05-14 23:49:44 -04:00
ret = ftrace_modify_code ( ip , old , new ) ;
return ret ;
}
2012-04-26 08:31:17 +00:00
static int __ftrace_replace_code ( struct dyn_ftrace * rec , int enable )
{
unsigned long ftrace_addr = ( unsigned long ) FTRACE_ADDR ;
int ret ;
ret = ftrace_update_record ( rec , enable ) ;
switch ( ret ) {
case FTRACE_UPDATE_IGNORE :
return 0 ;
case FTRACE_UPDATE_MAKE_CALL :
return ftrace_make_call ( rec , ftrace_addr ) ;
case FTRACE_UPDATE_MAKE_NOP :
return ftrace_make_nop ( NULL , rec , ftrace_addr ) ;
}
return 0 ;
}
void ftrace_replace_code ( int enable )
{
struct ftrace_rec_iter * iter ;
struct dyn_ftrace * rec ;
int ret ;
for ( iter = ftrace_rec_iter_start ( ) ; iter ;
iter = ftrace_rec_iter_next ( iter ) ) {
rec = ftrace_rec_iter_record ( iter ) ;
ret = __ftrace_replace_code ( rec , enable ) ;
if ( ret ) {
2014-10-24 17:56:04 -04:00
ftrace_bug ( ret , rec ) ;
2012-04-26 08:31:17 +00:00
return ;
}
}
}
void arch_ftrace_update_code ( int command )
{
if ( command & FTRACE_UPDATE_CALLS )
ftrace_replace_code ( 1 ) ;
else if ( command & FTRACE_DISABLE_CALLS )
ftrace_replace_code ( 0 ) ;
if ( command & FTRACE_UPDATE_TRACE_FUNC )
ftrace_update_ftrace_func ( ftrace_trace_function ) ;
if ( command & FTRACE_START_FUNC_RET )
ftrace_enable_ftrace_graph_caller ( ) ;
else if ( command & FTRACE_STOP_FUNC_RET )
ftrace_disable_ftrace_graph_caller ( ) ;
}
2014-02-24 19:59:59 +01:00
int __init ftrace_dyn_arch_init ( void )
2008-05-14 23:49:44 -04:00
{
return 0 ;
}
2009-02-09 21:10:27 -08:00
# endif /* CONFIG_DYNAMIC_FTRACE */
# ifdef CONFIG_FUNCTION_GRAPH_TRACER
2009-02-10 22:19:54 -08:00
# ifdef CONFIG_DYNAMIC_FTRACE
extern void ftrace_graph_call ( void ) ;
extern void ftrace_graph_stub ( void ) ;
int ftrace_enable_ftrace_graph_caller ( void )
{
unsigned long ip = ( unsigned long ) ( & ftrace_graph_call ) ;
unsigned long addr = ( unsigned long ) ( & ftrace_graph_caller ) ;
unsigned long stub = ( unsigned long ) ( & ftrace_graph_stub ) ;
2009-02-13 06:31:39 -08:00
unsigned int old , new ;
2009-02-10 22:19:54 -08:00
2009-02-13 06:31:39 -08:00
old = ftrace_call_replace ( ip , stub , 0 ) ;
2009-02-10 22:19:54 -08:00
new = ftrace_call_replace ( ip , addr , 0 ) ;
return ftrace_modify_code ( ip , old , new ) ;
}
int ftrace_disable_ftrace_graph_caller ( void )
{
unsigned long ip = ( unsigned long ) ( & ftrace_graph_call ) ;
unsigned long addr = ( unsigned long ) ( & ftrace_graph_caller ) ;
unsigned long stub = ( unsigned long ) ( & ftrace_graph_stub ) ;
2009-02-13 06:31:39 -08:00
unsigned int old , new ;
2009-02-10 22:19:54 -08:00
2009-02-13 06:31:39 -08:00
old = ftrace_call_replace ( ip , addr , 0 ) ;
2009-02-10 22:19:54 -08:00
new = ftrace_call_replace ( ip , stub , 0 ) ;
return ftrace_modify_code ( ip , old , new ) ;
}
# endif /* CONFIG_DYNAMIC_FTRACE */
2009-02-09 21:10:27 -08:00
/*
* Hook the return address and push it in the stack of return addrs
2014-09-17 17:07:04 +10:00
* in current thread info . Return the address we want to divert to .
2009-02-09 21:10:27 -08:00
*/
2014-09-17 17:07:04 +10:00
unsigned long prepare_ftrace_return ( unsigned long parent , unsigned long ip )
2009-02-09 21:10:27 -08:00
{
struct ftrace_graph_ent trace ;
2014-09-17 17:07:03 +10:00
unsigned long return_hooker ;
2009-02-09 21:10:27 -08:00
2014-06-25 10:27:30 -04:00
if ( unlikely ( ftrace_graph_is_dead ( ) ) )
2014-09-17 17:07:04 +10:00
goto out ;
2014-06-25 10:27:30 -04:00
2009-02-09 21:10:27 -08:00
if ( unlikely ( atomic_read ( & current - > tracing_graph_pause ) ) )
2014-09-17 17:07:04 +10:00
goto out ;
2009-02-09 21:10:27 -08:00
2014-09-17 17:07:03 +10:00
return_hooker = ppc_function_entry ( return_to_handler ) ;
2009-02-09 21:10:27 -08:00
2014-09-17 17:07:04 +10:00
trace . func = ip ;
2012-07-18 12:35:28 +00:00
trace . depth = current - > curr_ret_stack + 1 ;
2009-02-09 21:10:27 -08:00
/* Only trace if the calling function expects to */
2014-09-17 17:07:04 +10:00
if ( ! ftrace_graph_entry ( & trace ) )
goto out ;
if ( ftrace_push_return_trace ( parent , ip , & trace . depth , 0 ) = = - EBUSY )
goto out ;
2012-07-18 12:35:28 +00:00
2014-09-17 17:07:04 +10:00
parent = return_hooker ;
out :
return parent ;
2009-02-09 21:10:27 -08:00
}
# endif /* CONFIG_FUNCTION_GRAPH_TRACER */
2011-02-02 17:27:24 +00:00
# if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64)
unsigned long __init arch_syscall_addr ( int nr )
{
return sys_call_table [ nr * 2 ] ;
}
# endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 */