Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf64c800 authored by Paul Mundt's avatar Paul Mundt
Browse files

Merge branch 'sh/ftrace' of git://github.com/mfleming/linux-2.6

parents 512626a0 9e28c46b
Loading
Loading
Loading
Loading
+30 −30
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (C) 2008 Matt Fleming <mjf@gentoo.org>
 * Copyright (C) 2008 Matt Fleming <matt@console-pimps.org>
 * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org>
 * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org>
 *
 *
 * Code for replacing ftrace calls with jumps.
 * Code for replacing ftrace calls with jumps.
@@ -19,29 +19,36 @@
#include <asm/ftrace.h>
#include <asm/ftrace.h>
#include <asm/cacheflush.h>
#include <asm/cacheflush.h>


static unsigned char ftrace_nop[] = {
	0x09, 0x00,		/* nop */
	0x09, 0x00,		/* nop */
};

static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];


unsigned char *ftrace_nop_replace(void)
static unsigned char ftrace_nop[4];
/*
 * If we're trying to nop out a call to a function, we instead
 * place a call to the address after the memory table.
 *
 * 8c011060 <a>:
 * 8c011060:       02 d1           mov.l   8c01106c <a+0xc>,r1
 * 8c011062:       22 4f           sts.l   pr,@-r15
 * 8c011064:       02 c7           mova    8c011070 <a+0x10>,r0
 * 8c011066:       2b 41           jmp     @r1
 * 8c011068:       2a 40           lds     r0,pr
 * 8c01106a:       09 00           nop
 * 8c01106c:       68 24           .word 0x2468     <--- ip
 * 8c01106e:       1d 8c           .word 0x8c1d
 * 8c011070:       26 4f           lds.l   @r15+,pr <--- ip + MCOUNT_INSN_SIZE
 *
 * We write 0x8c011070 to 0x8c01106c so that on entry to a() we branch
 * past the _mcount call and continue executing code like normal.
 */
static unsigned char *ftrace_nop_replace(unsigned long ip)
{
{
	__raw_writel(ip + MCOUNT_INSN_SIZE, ftrace_nop);
	return ftrace_nop;
	return ftrace_nop;
}
}


static int is_sh_nop(unsigned char *ip)
static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
{
	return strncmp(ip, ftrace_nop, sizeof(ftrace_nop));
}

unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
{
{
	/* Place the address in the memory table. */
	/* Place the address in the memory table. */
	if (addr == CALLER_ADDR)
		__raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code);
	else
	__raw_writel(addr, ftrace_replaced_code);
	__raw_writel(addr, ftrace_replaced_code);


	/*
	/*
@@ -51,7 +58,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
	return ftrace_replaced_code;
	return ftrace_replaced_code;
}
}


int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
		       unsigned char *new_code)
		       unsigned char *new_code)
{
{
	unsigned char replaced[MCOUNT_INSN_SIZE];
	unsigned char replaced[MCOUNT_INSN_SIZE];
@@ -66,13 +73,6 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
	 * kstop_machine, or before SMP starts.
	 * kstop_machine, or before SMP starts.
	 */
	 */


	/*
	 * If we're trying to nop out a call to a function, we instead
	 * place a call to the address after the memory table.
	 */
	if (is_sh_nop(new_code) == 0)
		__raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code);

	/* read the text we want to modify */
	/* read the text we want to modify */
	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
	if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
		return -EFAULT;
		return -EFAULT;
@@ -92,13 +92,13 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code,


int ftrace_update_ftrace_func(ftrace_func_t func)
int ftrace_update_ftrace_func(ftrace_func_t func)
{
{
	unsigned long ip = (unsigned long)(&ftrace_call);
	unsigned long ip = (unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET;
	unsigned char old[MCOUNT_INSN_SIZE], *new;
	unsigned char old[MCOUNT_INSN_SIZE], *new;


	memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE);
	memcpy(old, (unsigned char *)ip, MCOUNT_INSN_SIZE);
	new = ftrace_call_replace(ip, (unsigned long)func);
	new = ftrace_call_replace(ip, (unsigned long)func);


	return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new);
	return ftrace_modify_code(ip, old, new);
}
}


int ftrace_make_nop(struct module *mod,
int ftrace_make_nop(struct module *mod,
@@ -108,7 +108,7 @@ int ftrace_make_nop(struct module *mod,
	unsigned long ip = rec->ip;
	unsigned long ip = rec->ip;


	old = ftrace_call_replace(ip, addr);
	old = ftrace_call_replace(ip, addr);
	new = ftrace_nop_replace();
	new = ftrace_nop_replace(ip);


	return ftrace_modify_code(rec->ip, old, new);
	return ftrace_modify_code(rec->ip, old, new);
}
}
@@ -118,7 +118,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
	unsigned char *new, *old;
	unsigned char *new, *old;
	unsigned long ip = rec->ip;
	unsigned long ip = rec->ip;


	old = ftrace_nop_replace();
	old = ftrace_nop_replace(ip);
	new = ftrace_call_replace(ip, addr);
	new = ftrace_call_replace(ip, addr);


	return ftrace_modify_code(rec->ip, old, new);
	return ftrace_modify_code(rec->ip, old, new);