aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace.h2
-rw-r--r--kernel/sysctl.c10
-rw-r--r--kernel/trace/trace.c29
-rw-r--r--scripts/tracing/draw_functrace.py130
4 files changed, 168 insertions, 3 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 703eb53cfa2b..899ec4b26b6c 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -181,6 +181,8 @@ static inline void __ftrace_enabled_restore(int enabled)
181#endif 181#endif
182 182
183#ifdef CONFIG_TRACING 183#ifdef CONFIG_TRACING
184extern int ftrace_dump_on_oops;
185
184extern void 186extern void
185ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3); 187ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3);
186 188
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9d048fa2d902..6b6b727258b5 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -484,6 +484,16 @@ static struct ctl_table kern_table[] = {
484 .proc_handler = &ftrace_enable_sysctl, 484 .proc_handler = &ftrace_enable_sysctl,
485 }, 485 },
486#endif 486#endif
487#ifdef CONFIG_TRACING
488 {
489 .ctl_name = CTL_UNNUMBERED,
490 .procname = "ftrace_dump_on_opps",
491 .data = &ftrace_dump_on_oops,
492 .maxlen = sizeof(int),
493 .mode = 0644,
494 .proc_handler = &proc_dointvec,
495 },
496#endif
487#ifdef CONFIG_MODULES 497#ifdef CONFIG_MODULES
488 { 498 {
489 .ctl_name = KERN_MODPROBE, 499 .ctl_name = KERN_MODPROBE,
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a610ca771558..8741e5c4313b 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -64,6 +64,28 @@ static cpumask_t __read_mostly tracing_buffer_mask;
64 64
65static int tracing_disabled = 1; 65static int tracing_disabled = 1;
66 66
67/*
68 * ftrace_dump_on_oops - variable to dump ftrace buffer on oops
69 *
70 * If there is an oops (or kernel panic) and the ftrace_dump_on_oops
71 * is set, then ftrace_dump is called. This will output the contents
72 * of the ftrace buffers to the console. This is very useful for
73 * capturing traces that lead to crashes and outputing it to a
74 * serial console.
75 *
76 * It is default off, but you can enable it with either specifying
77 * "ftrace_dump_on_oops" in the kernel command line, or setting
78 * /proc/sys/kernel/ftrace_dump_on_oops to true.
79 */
80int ftrace_dump_on_oops;
81
82static int __init set_ftrace_dump_on_oops(char *str)
83{
84 ftrace_dump_on_oops = 1;
85 return 1;
86}
87__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
88
67long 89long
68ns2usecs(cycle_t nsec) 90ns2usecs(cycle_t nsec)
69{ 91{
@@ -3020,7 +3042,8 @@ EXPORT_SYMBOL_GPL(__ftrace_printk);
3020static int trace_panic_handler(struct notifier_block *this, 3042static int trace_panic_handler(struct notifier_block *this,
3021 unsigned long event, void *unused) 3043 unsigned long event, void *unused)
3022{ 3044{
3023 ftrace_dump(); 3045 if (ftrace_dump_on_oops)
3046 ftrace_dump();
3024 return NOTIFY_OK; 3047 return NOTIFY_OK;
3025} 3048}
3026 3049
@@ -3036,7 +3059,8 @@ static int trace_die_handler(struct notifier_block *self,
3036{ 3059{
3037 switch (val) { 3060 switch (val) {
3038 case DIE_OOPS: 3061 case DIE_OOPS:
3039 ftrace_dump(); 3062 if (ftrace_dump_on_oops)
3063 ftrace_dump();
3040 break; 3064 break;
3041 default: 3065 default:
3042 break; 3066 break;
@@ -3077,7 +3101,6 @@ trace_printk_seq(struct trace_seq *s)
3077 trace_seq_reset(s); 3101 trace_seq_reset(s);
3078} 3102}
3079 3103
3080
3081void ftrace_dump(void) 3104void ftrace_dump(void)
3082{ 3105{
3083 static DEFINE_SPINLOCK(ftrace_dump_lock); 3106 static DEFINE_SPINLOCK(ftrace_dump_lock);
diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py
new file mode 100644
index 000000000000..902f9a992620
--- /dev/null
+++ b/scripts/tracing/draw_functrace.py
@@ -0,0 +1,130 @@
1#!/usr/bin/python
2
3"""
4Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
5Licensed under the terms of the GNU GPL License version 2
6
7This script parses a trace provided by the function tracer in
8kernel/trace/trace_functions.c
9The resulted trace is processed into a tree to produce a more human
10view of the call stack by drawing textual but hierarchical tree of
11calls. Only the functions's names and the the call time are provided.
12
13Usage:
14 Be sure that you have CONFIG_FUNCTION_TRACER
15 # mkdir /debugfs
16 # mount -t debug debug /debug
17 # echo function > /debug/tracing/current_tracer
18 $ cat /debug/tracing/trace_pipe > ~/raw_trace_func
19 Wait some times but not too much, the script is a bit slow.
20 Break the pipe (Ctrl + Z)
21 $ scripts/draw_functrace.py < raw_trace_func > draw_functrace
22 Then you have your drawn trace in draw_functrace
23"""
24
25
26import sys, re
27
28class CallTree:
29 """ This class provides a tree representation of the functions
30 call stack. If a function has no parent in the kernel (interrupt,
31 syscall, kernel thread...) then it is attached to a virtual parent
32 called ROOT.
33 """
34 ROOT = None
35
36 def __init__(self, func, time = None, parent = None):
37 self._func = func
38 self._time = time
39 if parent is None:
40 self._parent = CallTree.ROOT
41 else:
42 self._parent = parent
43 self._children = []
44
45 def calls(self, func, calltime):
46 """ If a function calls another one, call this method to insert it
47 into the tree at the appropriate place.
48 @return: A reference to the newly created child node.
49 """
50 child = CallTree(func, calltime, self)
51 self._children.append(child)
52 return child
53
54 def getParent(self, func):
55 """ Retrieve the last parent of the current node that
56 has the name given by func. If this function is not
57 on a parent, then create it as new child of root
58 @return: A reference to the parent.
59 """
60 tree = self
61 while tree != CallTree.ROOT and tree._func != func:
62 tree = tree._parent
63 if tree == CallTree.ROOT:
64 child = CallTree.ROOT.calls(func, None)
65 return child
66 return tree
67
68 def __repr__(self):
69 return self.__toString("", True)
70
71 def __toString(self, branch, lastChild):
72 if self._time is not None:
73 s = "%s----%s (%s)\n" % (branch, self._func, self._time)
74 else:
75 s = "%s----%s\n" % (branch, self._func)
76
77 i = 0
78 if lastChild:
79 branch = branch[:-1] + " "
80 while i < len(self._children):
81 if i != len(self._children) - 1:
82 s += "%s" % self._children[i].__toString(branch +\
83 " |", False)
84 else:
85 s += "%s" % self._children[i].__toString(branch +\
86 " |", True)
87 i += 1
88 return s
89
90class BrokenLineException(Exception):
91 """If the last line is not complete because of the pipe breakage,
92 we want to stop the processing and ignore this line.
93 """
94 pass
95
96class CommentLineException(Exception):
97 """ If the line is a comment (as in the beginning of the trace file),
98 just ignore it.
99 """
100 pass
101
102
103def parseLine(line):
104 line = line.strip()
105 if line.startswith("#"):
106 raise CommentLineException
107 m = re.match("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line)
108 if m is None:
109 raise BrokenLineException
110 return (m.group(1), m.group(2), m.group(3))
111
112
113def main():
114 CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
115 tree = CallTree.ROOT
116
117 for line in sys.stdin:
118 try:
119 calltime, callee, caller = parseLine(line)
120 except BrokenLineException:
121 break
122 except CommentLineException:
123 continue
124 tree = tree.getParent(caller)
125 tree = tree.calls(callee, calltime)
126
127 print CallTree.ROOT
128
129if __name__ == "__main__":
130 main()