hc
2024-08-13 f258bb3ae540ccc311fd344a0121bba1928b85dd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python
# SPDX-License-Identifier: GPL-2.0-only
 
"""
Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
 
This script parses a trace provided by the function tracer in
kernel/trace/trace_functions.c
The resulted trace is processed into a tree to produce a more human
view of the call stack by drawing textual but hierarchical tree of
calls. Only the functions's names and the the call time are provided.
 
Usage:
   Be sure that you have CONFIG_FUNCTION_TRACER
   # mount -t debugfs nodev /sys/kernel/debug
   # echo function > /sys/kernel/debug/tracing/current_tracer
   $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
   Wait some times but not too much, the script is a bit slow.
   Break the pipe (Ctrl + Z)
   $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
   Then you have your drawn trace in draw_functrace
"""
 
 
import sys, re
 
class CallTree:
   """ This class provides a tree representation of the functions
       call stack. If a function has no parent in the kernel (interrupt,
       syscall, kernel thread...) then it is attached to a virtual parent
       called ROOT.
   """
   ROOT = None
 
   def __init__(self, func, time = None, parent = None):
       self._func = func
       self._time = time
       if parent is None:
           self._parent = CallTree.ROOT
       else:
           self._parent = parent
       self._children = []
 
   def calls(self, func, calltime):
       """ If a function calls another one, call this method to insert it
           into the tree at the appropriate place.
           @return: A reference to the newly created child node.
       """
       child = CallTree(func, calltime, self)
       self._children.append(child)
       return child
 
   def getParent(self, func):
       """ Retrieve the last parent of the current node that
           has the name given by func. If this function is not
           on a parent, then create it as new child of root
           @return: A reference to the parent.
       """
       tree = self
       while tree != CallTree.ROOT and tree._func != func:
           tree = tree._parent
       if tree == CallTree.ROOT:
           child = CallTree.ROOT.calls(func, None)
           return child
       return tree
 
   def __repr__(self):
       return self.__toString("", True)
 
   def __toString(self, branch, lastChild):
       if self._time is not None:
           s = "%s----%s (%s)\n" % (branch, self._func, self._time)
       else:
           s = "%s----%s\n" % (branch, self._func)
 
       i = 0
       if lastChild:
           branch = branch[:-1] + " "
       while i < len(self._children):
           if i != len(self._children) - 1:
               s += "%s" % self._children[i].__toString(branch +\
                               "    |", False)
           else:
               s += "%s" % self._children[i].__toString(branch +\
                               "    |", True)
           i += 1
       return s
 
class BrokenLineException(Exception):
   """If the last line is not complete because of the pipe breakage,
      we want to stop the processing and ignore this line.
   """
   pass
 
class CommentLineException(Exception):
   """ If the line is a comment (as in the beginning of the trace file),
       just ignore it.
   """
   pass
 
 
def parseLine(line):
   line = line.strip()
   if line.startswith("#"):
       raise CommentLineException
   m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
   if m is None:
       raise BrokenLineException
   return (m.group(2), m.group(3), m.group(4))
 
 
def main():
   CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
   tree = CallTree.ROOT
 
   for line in sys.stdin:
       try:
           calltime, callee, caller = parseLine(line)
       except BrokenLineException:
           break
       except CommentLineException:
           continue
       tree = tree.getParent(caller)
       tree = tree.calls(callee, calltime)
 
   print(CallTree.ROOT)
 
if __name__ == "__main__":
   main()