aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions.c
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-03-13 10:17:50 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-03-15 00:36:05 -0400
commitdd42cd3ea96d687f15525c4f14fa582702db223f (patch)
tree135eb362cc41f54392d10af19fc4e10ef7060081 /kernel/trace/trace_functions.c
parentc142be8ebe0b7bf73c8a0063925623f3e4b980c0 (diff)
tracing: Add function probe to trigger stack traces
Add a function probe that will cause a stack trace to be traced in the ring buffer when the given function(s) are called. format is: <function>:stacktrace[:<count>] echo 'schedule:stacktrace' > /debug/tracing/set_ftrace_filter cat /debug/tracing/trace_pipe kworker/2:0-4329 [002] ...2 2933.558007: <stack trace> => kthread => ret_from_fork <idle>-0 [000] .N.2 2933.558019: <stack trace> => rest_init => start_kernel => x86_64_start_reservations => x86_64_start_kernel kworker/2:0-4329 [002] ...2 2933.558109: <stack trace> => kthread => ret_from_fork [...] This can be set to only trace a specific amount of times: echo 'schedule:stacktrace:3' > /debug/tracing/set_ftrace_filter cat /debug/tracing/trace_pipe <...>-58 [003] ...2 841.801694: <stack trace> => kthread => ret_from_fork <idle>-0 [001] .N.2 841.801697: <stack trace> => start_secondary <...>-2059 [001] ...2 841.801736: <stack trace> => wait_for_common => wait_for_completion => flush_work => tty_flush_to_ldisc => input_available_p => n_tty_poll => tty_poll => do_select => core_sys_select => sys_select => system_call_fastpath To remove these: echo '!schedule:stacktrace' > /debug/tracing/set_ftrace_filter echo '!schedule:stacktrace:0' > /debug/tracing/set_ftrace_filter Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace_functions.c')
-rw-r--r--kernel/trace/trace_functions.c150
1 files changed, 115 insertions, 35 deletions
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 043b2425ae73..c4d6d7191988 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -265,56 +265,103 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
265 tracing_off(); 265 tracing_off();
266} 266}
267 267
268/*
269 * Skip 4:
270 * ftrace_stacktrace()
271 * function_trace_probe_call()
272 * ftrace_ops_list_func()
273 * ftrace_call()
274 */
275#define STACK_SKIP 4
276
277static void
278ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data)
279{
280 trace_dump_stack(STACK_SKIP);
281}
282
283static void
284ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
285{
286 if (!tracing_is_on())
287 return;
288
289 if (update_count(data))
290 trace_dump_stack(STACK_SKIP);
291}
292
268static int 293static int
269ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip, 294ftrace_probe_print(const char *name, struct seq_file *m,
270 struct ftrace_probe_ops *ops, void *data); 295 unsigned long ip, void *data)
296{
297 long count = (long)data;
298
299 seq_printf(m, "%ps:%s", (void *)ip, name);
300
301 if (count == -1)
302 seq_printf(m, ":unlimited\n");
303 else
304 seq_printf(m, ":count=%ld\n", count);
305
306 return 0;
307}
308
309static int
310ftrace_traceon_print(struct seq_file *m, unsigned long ip,
311 struct ftrace_probe_ops *ops, void *data)
312{
313 return ftrace_probe_print("traceon", m, ip, data);
314}
315
316static int
317ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
318 struct ftrace_probe_ops *ops, void *data)
319{
320 return ftrace_probe_print("traceoff", m, ip, data);
321}
322
323static int
324ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
325 struct ftrace_probe_ops *ops, void *data)
326{
327 return ftrace_probe_print("stacktrace", m, ip, data);
328}
271 329
272static struct ftrace_probe_ops traceon_count_probe_ops = { 330static struct ftrace_probe_ops traceon_count_probe_ops = {
273 .func = ftrace_traceon_count, 331 .func = ftrace_traceon_count,
274 .print = ftrace_trace_onoff_print, 332 .print = ftrace_traceon_print,
275}; 333};
276 334
277static struct ftrace_probe_ops traceoff_count_probe_ops = { 335static struct ftrace_probe_ops traceoff_count_probe_ops = {
278 .func = ftrace_traceoff_count, 336 .func = ftrace_traceoff_count,
279 .print = ftrace_trace_onoff_print, 337 .print = ftrace_traceoff_print,
338};
339
340static struct ftrace_probe_ops stacktrace_count_probe_ops = {
341 .func = ftrace_stacktrace_count,
342 .print = ftrace_stacktrace_print,
280}; 343};
281 344
282static struct ftrace_probe_ops traceon_probe_ops = { 345static struct ftrace_probe_ops traceon_probe_ops = {
283 .func = ftrace_traceon, 346 .func = ftrace_traceon,
284 .print = ftrace_trace_onoff_print, 347 .print = ftrace_traceon_print,
285}; 348};
286 349
287static struct ftrace_probe_ops traceoff_probe_ops = { 350static struct ftrace_probe_ops traceoff_probe_ops = {
288 .func = ftrace_traceoff, 351 .func = ftrace_traceoff,
289 .print = ftrace_trace_onoff_print, 352 .print = ftrace_traceoff_print,
290}; 353};
291 354
292static int 355static struct ftrace_probe_ops stacktrace_probe_ops = {
293ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip, 356 .func = ftrace_stacktrace,
294 struct ftrace_probe_ops *ops, void *data) 357 .print = ftrace_stacktrace_print,
295{ 358};
296 long count = (long)data;
297
298 seq_printf(m, "%ps:", (void *)ip);
299
300 if (ops == &traceon_probe_ops || ops == &traceon_count_probe_ops)
301 seq_printf(m, "traceon");
302 else
303 seq_printf(m, "traceoff");
304
305 if (count == -1)
306 seq_printf(m, ":unlimited\n");
307 else
308 seq_printf(m, ":count=%ld\n", count);
309
310 return 0;
311}
312 359
313static int 360static int
314ftrace_trace_onoff_callback(struct ftrace_hash *hash, 361ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
315 char *glob, char *cmd, char *param, int enable) 362 struct ftrace_hash *hash, char *glob,
363 char *cmd, char *param, int enable)
316{ 364{
317 struct ftrace_probe_ops *ops;
318 void *count = (void *)-1; 365 void *count = (void *)-1;
319 char *number; 366 char *number;
320 int ret; 367 int ret;
@@ -323,12 +370,6 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
323 if (!enable) 370 if (!enable)
324 return -EINVAL; 371 return -EINVAL;
325 372
326 /* we register both traceon and traceoff to this callback */
327 if (strcmp(cmd, "traceon") == 0)
328 ops = param ? &traceon_count_probe_ops : &traceon_probe_ops;
329 else
330 ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
331
332 if (glob[0] == '!') { 373 if (glob[0] == '!') {
333 unregister_ftrace_function_probe_func(glob+1, ops); 374 unregister_ftrace_function_probe_func(glob+1, ops);
334 return 0; 375 return 0;
@@ -356,6 +397,34 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
356 return ret < 0 ? ret : 0; 397 return ret < 0 ? ret : 0;
357} 398}
358 399
400static int
401ftrace_trace_onoff_callback(struct ftrace_hash *hash,
402 char *glob, char *cmd, char *param, int enable)
403{
404 struct ftrace_probe_ops *ops;
405
406 /* we register both traceon and traceoff to this callback */
407 if (strcmp(cmd, "traceon") == 0)
408 ops = param ? &traceon_count_probe_ops : &traceon_probe_ops;
409 else
410 ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
411
412 return ftrace_trace_probe_callback(ops, hash, glob, cmd,
413 param, enable);
414}
415
416static int
417ftrace_stacktrace_callback(struct ftrace_hash *hash,
418 char *glob, char *cmd, char *param, int enable)
419{
420 struct ftrace_probe_ops *ops;
421
422 ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops;
423
424 return ftrace_trace_probe_callback(ops, hash, glob, cmd,
425 param, enable);
426}
427
359static struct ftrace_func_command ftrace_traceon_cmd = { 428static struct ftrace_func_command ftrace_traceon_cmd = {
360 .name = "traceon", 429 .name = "traceon",
361 .func = ftrace_trace_onoff_callback, 430 .func = ftrace_trace_onoff_callback,
@@ -366,6 +435,11 @@ static struct ftrace_func_command ftrace_traceoff_cmd = {
366 .func = ftrace_trace_onoff_callback, 435 .func = ftrace_trace_onoff_callback,
367}; 436};
368 437
438static struct ftrace_func_command ftrace_stacktrace_cmd = {
439 .name = "stacktrace",
440 .func = ftrace_stacktrace_callback,
441};
442
369static int __init init_func_cmd_traceon(void) 443static int __init init_func_cmd_traceon(void)
370{ 444{
371 int ret; 445 int ret;
@@ -377,6 +451,12 @@ static int __init init_func_cmd_traceon(void)
377 ret = register_ftrace_command(&ftrace_traceon_cmd); 451 ret = register_ftrace_command(&ftrace_traceon_cmd);
378 if (ret) 452 if (ret)
379 unregister_ftrace_command(&ftrace_traceoff_cmd); 453 unregister_ftrace_command(&ftrace_traceoff_cmd);
454
455 ret = register_ftrace_command(&ftrace_stacktrace_cmd);
456 if (ret) {
457 unregister_ftrace_command(&ftrace_traceoff_cmd);
458 unregister_ftrace_command(&ftrace_traceon_cmd);
459 }
380 return ret; 460 return ret;
381} 461}
382#else 462#else