diff options
author | Steven Rostedt <srostedt@redhat.com> | 2008-05-12 15:20:43 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-23 14:33:47 -0400 |
commit | d61f82d06672f57fca410da6f7fffd15867db622 (patch) | |
tree | 62ef5573934eaa638c0d39a45d789691aecbd7d3 /arch/x86/kernel/ftrace.c | |
parent | 3c1720f00bb619302ba19d55986ab565e74d06db (diff) |
ftrace: use dynamic patching for updating mcount calls
This patch replaces the indirect call to the mcount function
pointer with a direct call that will be patched by the
dynamic ftrace routines.
On boot up, the mcount function calls the ftace_stub function.
When the dynamic ftrace code is initialized, the ftrace_stub
is replaced with a call to the ftrace_record_ip, which records
the instruction pointers of the locations that call it.
Later, the ftraced daemon will call kstop_machine and patch all
the locations to nops.
When a ftrace is enabled, the original calls to mcount will now
be set top call ftrace_caller, which will do a direct call
to the registered ftrace function. This direct call is also patched
when the function that should be called is updated.
All patching is performed by a kstop_machine routine to prevent any
type of race conditions that is associated with modifying code
on the fly.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/ftrace.c')
-rw-r--r-- | arch/x86/kernel/ftrace.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index b69795efa226..9f44623e0072 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
@@ -109,10 +109,49 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
109 | return faulted; | 109 | return faulted; |
110 | } | 110 | } |
111 | 111 | ||
112 | int __init ftrace_dyn_arch_init(void) | 112 | notrace int ftrace_update_ftrace_func(ftrace_func_t func) |
113 | { | ||
114 | unsigned long ip = (unsigned long)(&ftrace_call); | ||
115 | unsigned char old[5], *new; | ||
116 | int ret; | ||
117 | |||
118 | ip += CALL_BACK; | ||
119 | |||
120 | memcpy(old, &ftrace_call, 5); | ||
121 | new = ftrace_call_replace(ip, (unsigned long)func); | ||
122 | ret = ftrace_modify_code(ip, old, new); | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | notrace int ftrace_mcount_set(unsigned long *data) | ||
128 | { | ||
129 | unsigned long ip = (long)(&mcount_call); | ||
130 | unsigned long *addr = data; | ||
131 | unsigned char old[5], *new; | ||
132 | |||
133 | /* ip is at the location, but modify code will subtact this */ | ||
134 | ip += CALL_BACK; | ||
135 | |||
136 | /* | ||
137 | * Replace the mcount stub with a pointer to the | ||
138 | * ip recorder function. | ||
139 | */ | ||
140 | memcpy(old, &mcount_call, 5); | ||
141 | new = ftrace_call_replace(ip, *addr); | ||
142 | *addr = ftrace_modify_code(ip, old, new); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | int __init ftrace_dyn_arch_init(void *data) | ||
113 | { | 148 | { |
114 | const unsigned char *const *noptable = find_nop_table(); | 149 | const unsigned char *const *noptable = find_nop_table(); |
115 | 150 | ||
151 | /* This is running in kstop_machine */ | ||
152 | |||
153 | ftrace_mcount_set(data); | ||
154 | |||
116 | ftrace_nop = (unsigned long *)noptable[CALL_BACK]; | 155 | ftrace_nop = (unsigned long *)noptable[CALL_BACK]; |
117 | 156 | ||
118 | return 0; | 157 | return 0; |