Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 121123
b: refs/heads/master
c: 31e8890
h: refs/heads/master
i:
  121121: f4d368a
  121119: b0b545d
v: v3
  • Loading branch information
Steven Rostedt authored and Ingo Molnar committed Nov 16, 2008
1 parent 0b83517 commit 42a9cd3
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d51ad7ac48f991c4a8834485727efa99a691cb87
refs/heads/master: 31e889098a80ceb3e9e3c555d522b2686a6663c6
8 changes: 8 additions & 0 deletions trunk/arch/x86/include/asm/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
*/
return addr - 1;
}

#ifdef CONFIG_DYNAMIC_FTRACE

struct dyn_arch_ftrace {
/* No extra data needed for x86 */
};

#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */

Expand Down
29 changes: 26 additions & 3 deletions trunk/arch/x86/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ static int ftrace_calc_offset(long ip, long addr)
return (int)(addr - ip);
}

unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
{
static union ftrace_code_union calc;

Expand Down Expand Up @@ -311,12 +311,12 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)

static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];

unsigned char *ftrace_nop_replace(void)
static unsigned char *ftrace_nop_replace(void)
{
return ftrace_nop;
}

int
static int
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code)
{
Expand Down Expand Up @@ -349,6 +349,29 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
return 0;
}

int ftrace_make_nop(struct module *mod,
struct dyn_ftrace *rec, unsigned long addr)
{
unsigned char *new, *old;
unsigned long ip = rec->ip;

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

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

int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
unsigned char *new, *old;
unsigned long ip = rec->ip;

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

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

int ftrace_update_ftrace_func(ftrace_func_t func)
{
unsigned long ip = (unsigned long)(&ftrace_call);
Expand Down
53 changes: 41 additions & 12 deletions trunk/include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ static inline void ftrace_start(void) { }
#endif /* CONFIG_FUNCTION_TRACER */

#ifdef CONFIG_DYNAMIC_FTRACE
/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
#include <asm/ftrace.h>

enum {
FTRACE_FL_FREE = (1 << 0),
FTRACE_FL_FAILED = (1 << 1),
Expand All @@ -88,45 +91,69 @@ struct dyn_ftrace {
struct list_head list;
unsigned long ip; /* address of mcount call-site */
unsigned long flags;
struct dyn_arch_ftrace arch;
};

int ftrace_force_update(void);
void ftrace_set_filter(unsigned char *buf, int len, int reset);

/* defined in arch */
extern int ftrace_ip_converted(unsigned long ip);
extern unsigned char *ftrace_nop_replace(void);
extern unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr);
extern int ftrace_dyn_arch_init(void *data);
extern int ftrace_update_ftrace_func(ftrace_func_t func);
extern void ftrace_caller(void);
extern void ftrace_call(void);
extern void mcount_call(void);

/* May be defined in arch */
extern int ftrace_arch_read_dyn_info(char *buf, int size);
/**
* ftrace_make_nop - convert code into top
* @mod: module structure if called by module load initialization
* @rec: the mcount call site record
* @addr: the address that the call site should be calling
*
* This is a very sensitive operation and great care needs
* to be taken by the arch. The operation should carefully
* read the location, check to see if what is read is indeed
* what we expect it to be, and then on success of the compare,
* it should write to the location.
*
* The code segment at @rec->ip should be a caller to @addr
*
* Return must be:
* 0 on success
* -EFAULT on error reading the location
* -EINVAL on a failed compare of the contents
* -EPERM on error writing to the location
* Any other value will be considered a failure.
*/
extern int ftrace_make_nop(struct module *mod,
struct dyn_ftrace *rec, unsigned long addr);

/**
* ftrace_modify_code - modify code segment
* @ip: the address of the code segment
* @old_code: the contents of what is expected to be there
* @new_code: the code to patch in
* ftrace_make_call - convert a nop call site into a call to addr
* @rec: the mcount call site record
* @addr: the address that the call site should call
*
* This is a very sensitive operation and great care needs
* to be taken by the arch. The operation should carefully
* read the location, check to see if what is read is indeed
* what we expect it to be, and then on success of the compare,
* it should write to the location.
*
* The code segment at @rec->ip should be a nop
*
* Return must be:
* 0 on success
* -EFAULT on error reading the location
* -EINVAL on a failed compare of the contents
* -EPERM on error writing to the location
* Any other value will be considered a failure.
*/
extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code);
extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);


/* May be defined in arch */
extern int ftrace_arch_read_dyn_info(char *buf, int size);

extern int skip_trace(unsigned long ip);

Expand Down Expand Up @@ -259,11 +286,13 @@ static inline void ftrace_dump(void) { }

#ifdef CONFIG_FTRACE_MCOUNT_RECORD
extern void ftrace_init(void);
extern void ftrace_init_module(unsigned long *start, unsigned long *end);
extern void ftrace_init_module(struct module *mod,
unsigned long *start, unsigned long *end);
#else
static inline void ftrace_init(void) { }
static inline void
ftrace_init_module(unsigned long *start, unsigned long *end) { }
ftrace_init_module(struct module *mod,
unsigned long *start, unsigned long *end) { }
#endif


Expand Down
2 changes: 1 addition & 1 deletion trunk/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -2201,7 +2201,7 @@ static noinline struct module *load_module(void __user *umod,
/* sechdrs[0].sh_size is always zero */
mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc",
sizeof(*mseg), &num_mcount);
ftrace_init_module(mseg, mseg + num_mcount);
ftrace_init_module(mod, mseg, mseg + num_mcount);

err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
Expand Down
62 changes: 24 additions & 38 deletions trunk/kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,7 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
}

static void ftrace_bug(int failed, unsigned long ip,
unsigned char *expected,
unsigned char *replace)
static void ftrace_bug(int failed, unsigned long ip)
{
switch (failed) {
case -EFAULT:
Expand All @@ -372,9 +370,7 @@ static void ftrace_bug(int failed, unsigned long ip,
FTRACE_WARN_ON_ONCE(1);
pr_info("ftrace failed to modify ");
print_ip_sym(ip);
print_ip_ins(" expected: ", expected);
print_ip_ins(" actual: ", (unsigned char *)ip);
print_ip_ins(" replace: ", replace);
printk(KERN_CONT "\n");
break;
case -EPERM:
Expand All @@ -392,8 +388,7 @@ static void ftrace_bug(int failed, unsigned long ip,
#define FTRACE_ADDR ((long)(ftrace_caller))

static int
__ftrace_replace_code(struct dyn_ftrace *rec,
unsigned char *old, unsigned char *new, int enable)
__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
{
unsigned long ip, fl;

Expand Down Expand Up @@ -435,12 +430,10 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
* otherwise enable it!
*/
if (fl & FTRACE_FL_ENABLED) {
/* swap new and old */
new = old;
old = ftrace_call_replace(ip, FTRACE_ADDR);
enable = 0;
rec->flags &= ~FTRACE_FL_ENABLED;
} else {
new = ftrace_call_replace(ip, FTRACE_ADDR);
enable = 1;
rec->flags |= FTRACE_FL_ENABLED;
}
} else {
Expand All @@ -453,10 +446,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
fl = rec->flags & (FTRACE_FL_NOTRACE | FTRACE_FL_ENABLED);
if (fl == FTRACE_FL_NOTRACE)
return 0;

new = ftrace_call_replace(ip, FTRACE_ADDR);
} else
old = ftrace_call_replace(ip, FTRACE_ADDR);
}

if (enable) {
if (rec->flags & FTRACE_FL_ENABLED)
Expand All @@ -469,21 +459,18 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
}
}

return ftrace_modify_code(ip, old, new);
if (enable)
return ftrace_make_call(rec, FTRACE_ADDR);
else
return ftrace_make_nop(NULL, rec, FTRACE_ADDR);
}

static void ftrace_replace_code(int enable)
{
int i, failed;
unsigned char *new = NULL, *old = NULL;
struct dyn_ftrace *rec;
struct ftrace_page *pg;

if (enable)
old = ftrace_nop_replace();
else
new = ftrace_nop_replace();

for (pg = ftrace_pages_start; pg; pg = pg->next) {
for (i = 0; i < pg->index; i++) {
rec = &pg->records[i];
Expand All @@ -504,34 +491,30 @@ static void ftrace_replace_code(int enable)
unfreeze_record(rec);
}

failed = __ftrace_replace_code(rec, old, new, enable);
failed = __ftrace_replace_code(rec, enable);
if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
rec->flags |= FTRACE_FL_FAILED;
if ((system_state == SYSTEM_BOOTING) ||
!core_kernel_text(rec->ip)) {
ftrace_free_rec(rec);
} else
ftrace_bug(failed, rec->ip, old, new);
ftrace_bug(failed, rec->ip);
}
}
}
}

static int
ftrace_code_disable(struct dyn_ftrace *rec)
ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
{
unsigned long ip;
unsigned char *nop, *call;
int ret;

ip = rec->ip;

nop = ftrace_nop_replace();
call = ftrace_call_replace(ip, mcount_addr);

ret = ftrace_modify_code(ip, call, nop);
ret = ftrace_make_nop(mod, rec, mcount_addr);
if (ret) {
ftrace_bug(ret, ip, call, nop);
ftrace_bug(ret, ip);
rec->flags |= FTRACE_FL_FAILED;
return 0;
}
Expand Down Expand Up @@ -650,7 +633,7 @@ static cycle_t ftrace_update_time;
static unsigned long ftrace_update_cnt;
unsigned long ftrace_update_tot_cnt;

static int ftrace_update_code(void)
static int ftrace_update_code(struct module *mod)
{
struct dyn_ftrace *p, *t;
cycle_t start, stop;
Expand All @@ -667,7 +650,7 @@ static int ftrace_update_code(void)
list_del_init(&p->list);

/* convert record (i.e, patch mcount-call with NOP) */
if (ftrace_code_disable(p)) {
if (ftrace_code_disable(mod, p)) {
p->flags |= FTRACE_FL_CONVERTED;
ftrace_update_cnt++;
} else
Expand Down Expand Up @@ -1309,7 +1292,8 @@ static __init int ftrace_init_debugfs(void)

fs_initcall(ftrace_init_debugfs);

static int ftrace_convert_nops(unsigned long *start,
static int ftrace_convert_nops(struct module *mod,
unsigned long *start,
unsigned long *end)
{
unsigned long *p;
Expand All @@ -1325,18 +1309,19 @@ static int ftrace_convert_nops(unsigned long *start,

/* disable interrupts to prevent kstop machine */
local_irq_save(flags);
ftrace_update_code();
ftrace_update_code(mod);
local_irq_restore(flags);
mutex_unlock(&ftrace_start_lock);

return 0;
}

void ftrace_init_module(unsigned long *start, unsigned long *end)
void ftrace_init_module(struct module *mod,
unsigned long *start, unsigned long *end)
{
if (ftrace_disabled || start == end)
return;
ftrace_convert_nops(start, end);
ftrace_convert_nops(mod, start, end);
}

extern unsigned long __start_mcount_loc[];
Expand Down Expand Up @@ -1366,7 +1351,8 @@ void __init ftrace_init(void)

last_ftrace_enabled = ftrace_enabled = 1;

ret = ftrace_convert_nops(__start_mcount_loc,
ret = ftrace_convert_nops(NULL,
__start_mcount_loc,
__stop_mcount_loc);

return;
Expand Down

0 comments on commit 42a9cd3

Please sign in to comment.