aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ftrace.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-05-12 15:20:43 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 14:33:47 -0400
commitd61f82d06672f57fca410da6f7fffd15867db622 (patch)
tree62ef5573934eaa638c0d39a45d789691aecbd7d3 /arch/x86/kernel/ftrace.c
parent3c1720f00bb619302ba19d55986ab565e74d06db (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.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index b69795efa22..9f44623e007 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
112int __init ftrace_dyn_arch_init(void) 112notrace 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
127notrace 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
147int __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;