diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2009-09-14 16:49:20 -0400 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2009-09-16 22:03:54 -0400 |
commit | 50d780560785b068c358675c5f0bf6c83b5c373e (patch) | |
tree | 23baa2c37e12207778a7104e9b9e0d7fec5bee62 /kernel/trace/trace_kprobe.c | |
parent | 4fead8e46fded93cc0d432ced774d9a3a8d21bad (diff) |
tracing/kprobes: Add probe handler dispatcher to support perf and ftrace concurrent use
Add kprobe_dispatcher and kretprobe_dispatcher to dispatch event
in both profile and tracing handlers.
This allows simultaneous kprobe uses by ftrace and perf.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jason Baron <jbaron@redhat.com>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <20090914204920.18779.57555.stgit@dhcp-100-2-132.bos.redhat.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'kernel/trace/trace_kprobe.c')
-rw-r--r-- | kernel/trace/trace_kprobe.c | 85 |
1 files changed, 63 insertions, 22 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index ea0db8eee570..70b632c3bd08 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -185,10 +185,15 @@ struct probe_arg { | |||
185 | const char *name; | 185 | const char *name; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | /* Flags for trace_probe */ | ||
189 | #define TP_FLAG_TRACE 1 | ||
190 | #define TP_FLAG_PROFILE 2 | ||
191 | |||
188 | struct trace_probe { | 192 | struct trace_probe { |
189 | struct list_head list; | 193 | struct list_head list; |
190 | struct kretprobe rp; /* Use rp.kp for kprobe use */ | 194 | struct kretprobe rp; /* Use rp.kp for kprobe use */ |
191 | unsigned long nhit; | 195 | unsigned long nhit; |
196 | unsigned int flags; /* For TP_FLAG_* */ | ||
192 | const char *symbol; /* symbol name */ | 197 | const char *symbol; /* symbol name */ |
193 | struct ftrace_event_call call; | 198 | struct ftrace_event_call call; |
194 | struct trace_event event; | 199 | struct trace_event event; |
@@ -200,10 +205,6 @@ struct trace_probe { | |||
200 | (offsetof(struct trace_probe, args) + \ | 205 | (offsetof(struct trace_probe, args) + \ |
201 | (sizeof(struct probe_arg) * (n))) | 206 | (sizeof(struct probe_arg) * (n))) |
202 | 207 | ||
203 | static int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs); | ||
204 | static int kretprobe_trace_func(struct kretprobe_instance *ri, | ||
205 | struct pt_regs *regs); | ||
206 | |||
207 | static __kprobes int probe_is_return(struct trace_probe *tp) | 208 | static __kprobes int probe_is_return(struct trace_probe *tp) |
208 | { | 209 | { |
209 | return tp->rp.handler != NULL; | 210 | return tp->rp.handler != NULL; |
@@ -263,6 +264,10 @@ static void unregister_probe_event(struct trace_probe *tp); | |||
263 | static DEFINE_MUTEX(probe_lock); | 264 | static DEFINE_MUTEX(probe_lock); |
264 | static LIST_HEAD(probe_list); | 265 | static LIST_HEAD(probe_list); |
265 | 266 | ||
267 | static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); | ||
268 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, | ||
269 | struct pt_regs *regs); | ||
270 | |||
266 | /* | 271 | /* |
267 | * Allocate new trace_probe and initialize it (including kprobes). | 272 | * Allocate new trace_probe and initialize it (including kprobes). |
268 | */ | 273 | */ |
@@ -288,11 +293,10 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
288 | } else | 293 | } else |
289 | tp->rp.kp.addr = addr; | 294 | tp->rp.kp.addr = addr; |
290 | 295 | ||
291 | /* Set handler here for checking whether this probe is return or not. */ | ||
292 | if (is_return) | 296 | if (is_return) |
293 | tp->rp.handler = kretprobe_trace_func; | 297 | tp->rp.handler = kretprobe_dispatcher; |
294 | else | 298 | else |
295 | tp->rp.kp.pre_handler = kprobe_trace_func; | 299 | tp->rp.kp.pre_handler = kprobe_dispatcher; |
296 | 300 | ||
297 | if (!event) | 301 | if (!event) |
298 | goto error; | 302 | goto error; |
@@ -379,6 +383,7 @@ static int register_trace_probe(struct trace_probe *tp) | |||
379 | goto end; | 383 | goto end; |
380 | } | 384 | } |
381 | 385 | ||
386 | tp->flags = TP_FLAG_TRACE; | ||
382 | if (probe_is_return(tp)) | 387 | if (probe_is_return(tp)) |
383 | ret = register_kretprobe(&tp->rp); | 388 | ret = register_kretprobe(&tp->rp); |
384 | else | 389 | else |
@@ -987,23 +992,24 @@ static int probe_event_enable(struct ftrace_event_call *call) | |||
987 | { | 992 | { |
988 | struct trace_probe *tp = (struct trace_probe *)call->data; | 993 | struct trace_probe *tp = (struct trace_probe *)call->data; |
989 | 994 | ||
990 | if (probe_is_return(tp)) { | 995 | tp->flags |= TP_FLAG_TRACE; |
991 | tp->rp.handler = kretprobe_trace_func; | 996 | if (probe_is_return(tp)) |
992 | return enable_kretprobe(&tp->rp); | 997 | return enable_kretprobe(&tp->rp); |
993 | } else { | 998 | else |
994 | tp->rp.kp.pre_handler = kprobe_trace_func; | ||
995 | return enable_kprobe(&tp->rp.kp); | 999 | return enable_kprobe(&tp->rp.kp); |
996 | } | ||
997 | } | 1000 | } |
998 | 1001 | ||
999 | static void probe_event_disable(struct ftrace_event_call *call) | 1002 | static void probe_event_disable(struct ftrace_event_call *call) |
1000 | { | 1003 | { |
1001 | struct trace_probe *tp = (struct trace_probe *)call->data; | 1004 | struct trace_probe *tp = (struct trace_probe *)call->data; |
1002 | 1005 | ||
1003 | if (probe_is_return(tp)) | 1006 | tp->flags &= ~TP_FLAG_TRACE; |
1004 | disable_kretprobe(&tp->rp); | 1007 | if (!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE))) { |
1005 | else | 1008 | if (probe_is_return(tp)) |
1006 | disable_kprobe(&tp->rp.kp); | 1009 | disable_kretprobe(&tp->rp); |
1010 | else | ||
1011 | disable_kprobe(&tp->rp.kp); | ||
1012 | } | ||
1007 | } | 1013 | } |
1008 | 1014 | ||
1009 | static int probe_event_raw_init(struct ftrace_event_call *event_call) | 1015 | static int probe_event_raw_init(struct ftrace_event_call *event_call) |
@@ -1212,22 +1218,57 @@ static int probe_profile_enable(struct ftrace_event_call *call) | |||
1212 | if (atomic_inc_return(&call->profile_count)) | 1218 | if (atomic_inc_return(&call->profile_count)) |
1213 | return 0; | 1219 | return 0; |
1214 | 1220 | ||
1215 | if (probe_is_return(tp)) { | 1221 | tp->flags |= TP_FLAG_PROFILE; |
1216 | tp->rp.handler = kretprobe_profile_func; | 1222 | if (probe_is_return(tp)) |
1217 | return enable_kretprobe(&tp->rp); | 1223 | return enable_kretprobe(&tp->rp); |
1218 | } else { | 1224 | else |
1219 | tp->rp.kp.pre_handler = kprobe_profile_func; | ||
1220 | return enable_kprobe(&tp->rp.kp); | 1225 | return enable_kprobe(&tp->rp.kp); |
1221 | } | ||
1222 | } | 1226 | } |
1223 | 1227 | ||
1224 | static void probe_profile_disable(struct ftrace_event_call *call) | 1228 | static void probe_profile_disable(struct ftrace_event_call *call) |
1225 | { | 1229 | { |
1230 | struct trace_probe *tp = (struct trace_probe *)call->data; | ||
1231 | |||
1226 | if (atomic_add_negative(-1, &call->profile_count)) | 1232 | if (atomic_add_negative(-1, &call->profile_count)) |
1227 | probe_event_disable(call); | 1233 | tp->flags &= ~TP_FLAG_PROFILE; |
1234 | |||
1235 | if (!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE))) { | ||
1236 | if (probe_is_return(tp)) | ||
1237 | disable_kretprobe(&tp->rp); | ||
1238 | else | ||
1239 | disable_kprobe(&tp->rp.kp); | ||
1240 | } | ||
1228 | } | 1241 | } |
1242 | #endif /* CONFIG_EVENT_PROFILE */ | ||
1243 | |||
1244 | |||
1245 | static __kprobes | ||
1246 | int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) | ||
1247 | { | ||
1248 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); | ||
1229 | 1249 | ||
1250 | if (tp->flags & TP_FLAG_TRACE) | ||
1251 | kprobe_trace_func(kp, regs); | ||
1252 | #ifdef CONFIG_EVENT_PROFILE | ||
1253 | if (tp->flags & TP_FLAG_PROFILE) | ||
1254 | kprobe_profile_func(kp, regs); | ||
1230 | #endif /* CONFIG_EVENT_PROFILE */ | 1255 | #endif /* CONFIG_EVENT_PROFILE */ |
1256 | return 0; /* We don't tweek kernel, so just return 0 */ | ||
1257 | } | ||
1258 | |||
1259 | static __kprobes | ||
1260 | int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) | ||
1261 | { | ||
1262 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | ||
1263 | |||
1264 | if (tp->flags & TP_FLAG_TRACE) | ||
1265 | kretprobe_trace_func(ri, regs); | ||
1266 | #ifdef CONFIG_EVENT_PROFILE | ||
1267 | if (tp->flags & TP_FLAG_PROFILE) | ||
1268 | kretprobe_profile_func(ri, regs); | ||
1269 | #endif /* CONFIG_EVENT_PROFILE */ | ||
1270 | return 0; /* We don't tweek kernel, so just return 0 */ | ||
1271 | } | ||
1231 | 1272 | ||
1232 | static int register_probe_event(struct trace_probe *tp) | 1273 | static int register_probe_event(struct trace_probe *tp) |
1233 | { | 1274 | { |