Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 100428
b: refs/heads/master
c: 3c1720f
h: refs/heads/master
v: v3
  • Loading branch information
Steven Rostedt authored and Thomas Gleixner committed May 23, 2008
1 parent 32dacc5 commit aabd015
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 164 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: dfa60aba04dae7833d75b2e2be124bb7cfb8239f
refs/heads/master: 3c1720f00bb619302ba19d55986ab565e74d06db
183 changes: 29 additions & 154 deletions trunk/arch/x86/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,6 @@
/* Long is fine, even if it is only 4 bytes ;-) */
static long *ftrace_nop;

struct ftrace_record {
struct dyn_ftrace rec;
int failed;
} __attribute__((packed));

struct ftrace_page {
struct ftrace_page *next;
int index;
struct ftrace_record records[];
} __attribute__((packed));

#define ENTRIES_PER_PAGE \
((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct ftrace_record))

/* estimate from running different kernels */
#define NR_TO_INIT 10000

#define MCOUNT_ADDR ((long)(&mcount))

union ftrace_code_union {
char code[5];
struct {
Expand All @@ -50,33 +31,41 @@ union ftrace_code_union {
} __attribute__((packed));
};

static struct ftrace_page *ftrace_pages_start;
static struct ftrace_page *ftrace_pages;

notrace struct dyn_ftrace *ftrace_alloc_shutdown_node(unsigned long ip)
notrace int ftrace_ip_converted(unsigned long ip)
{
struct ftrace_record *rec;
unsigned long save;

ip -= CALL_BACK;
save = *(long *)ip;

/* If this was already converted, skip it */
if (save == *ftrace_nop)
return NULL;
return save == *ftrace_nop;
}

if (ftrace_pages->index == ENTRIES_PER_PAGE) {
if (!ftrace_pages->next)
return NULL;
ftrace_pages = ftrace_pages->next;
}
static int notrace ftrace_calc_offset(long ip, long addr)
{
return (int)(addr - ip);
}

rec = &ftrace_pages->records[ftrace_pages->index++];
notrace unsigned char *ftrace_nop_replace(void)
{
return (char *)ftrace_nop;
}

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

return &rec->rec;
calc.e8 = 0xe8;
calc.offset = ftrace_calc_offset(ip, addr);

/*
* No locking needed, this must be called via kstop_machine
* which in essence is like running on a uniprocessor machine.
*/
return calc.code;
}

static int notrace
notrace int
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code)
{
Expand All @@ -86,6 +75,9 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char newch = new_code[4];
int faulted = 0;

/* move the IP back to the start of the call */
ip -= CALL_BACK;

/*
* Note: Due to modules and __init, code can
* disappear and change, we need to protect against faulting
Expand Down Expand Up @@ -117,129 +109,12 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
return faulted;
}

static int notrace ftrace_calc_offset(long ip)
{
return (int)(MCOUNT_ADDR - ip);
}

notrace void ftrace_code_disable(struct dyn_ftrace *rec)
{
unsigned long ip;
union ftrace_code_union save;
struct ftrace_record *r =
container_of(rec, struct ftrace_record, rec);

ip = rec->ip;

save.e8 = 0xe8;
save.offset = ftrace_calc_offset(ip);

/* move the IP back to the start of the call */
ip -= CALL_BACK;

r->failed = ftrace_modify_code(ip, save.code, (char *)ftrace_nop);
}

static void notrace ftrace_replace_code(int saved)
{
unsigned char *new = NULL, *old = NULL;
struct ftrace_record *rec;
struct ftrace_page *pg;
unsigned long ip;
int i;

if (saved)
old = (char *)ftrace_nop;
else
new = (char *)ftrace_nop;

for (pg = ftrace_pages_start; pg; pg = pg->next) {
for (i = 0; i < pg->index; i++) {
union ftrace_code_union calc;
rec = &pg->records[i];

/* don't modify code that has already faulted */
if (rec->failed)
continue;

ip = rec->rec.ip;

calc.e8 = 0xe8;
calc.offset = ftrace_calc_offset(ip);

if (saved)
new = calc.code;
else
old = calc.code;

ip -= CALL_BACK;

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

}

notrace void ftrace_startup_code(void)
{
ftrace_replace_code(1);
}

notrace void ftrace_shutdown_code(void)
{
ftrace_replace_code(0);
}

notrace void ftrace_shutdown_replenish(void)
{
if (ftrace_pages->next)
return;

/* allocate another page */
ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
}

notrace int __init ftrace_shutdown_arch_init(void)
int __init ftrace_dyn_arch_init(void)
{
const unsigned char *const *noptable = find_nop_table();
struct ftrace_page *pg;
int cnt;
int i;

ftrace_nop = (unsigned long *)noptable[CALL_BACK];

/* allocate a few pages */
ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
if (!ftrace_pages_start)
return -1;

/*
* Allocate a few more pages.
*
* TODO: have some parser search vmlinux before
* final linking to find all calls to ftrace.
* Then we can:
* a) know how many pages to allocate.
* and/or
* b) set up the table then.
*
* The dynamic code is still necessary for
* modules.
*/

pg = ftrace_pages = ftrace_pages_start;

cnt = NR_TO_INIT / ENTRIES_PER_PAGE;

for (i = 0; i < cnt; i++) {
pg->next = (void *)get_zeroed_page(GFP_KERNEL);

/* If we fail, we'll try later anyway */
if (!pg->next)
break;

pg = pg->next;
}

return 0;
}

18 changes: 11 additions & 7 deletions trunk/include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,23 @@ extern void mcount(void);
# define FTRACE_HASHBITS 10
# define FTRACE_HASHSIZE (1<<FTRACE_HASHBITS)

enum {
FTRACE_FL_FAILED = (1<<0),
};

struct dyn_ftrace {
struct hlist_node node;
unsigned long ip;
unsigned long flags;
};

/* defined in arch */
extern struct dyn_ftrace *
ftrace_alloc_shutdown_node(unsigned long ip);
extern int ftrace_shutdown_arch_init(void);
extern void ftrace_code_disable(struct dyn_ftrace *rec);
extern void ftrace_startup_code(void);
extern void ftrace_shutdown_code(void);
extern void ftrace_shutdown_replenish(void);
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);
extern int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code);
#endif

#ifdef CONFIG_FRAME_POINTER
Expand Down
Loading

0 comments on commit aabd015

Please sign in to comment.