263a5b497dc2aeddd77aef1afedae107a2c116a4
[staptrace.git] / src / staptrace.stp
1 #! /usr/bin/stap
2
3 # Copyright (C) 2010 Free Software Foundation, Inc.
4
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 # ` = 0' is there to prevent: WARNING: never-assigned global variable
19
20 # `opt_f' is a boolean for both -f and -ff.
21 global opt_f = 0
22 # Modify the [pid %5d] output to [%d] for the -ff postprocessor.
23 global opt_ff = 0
24 global opt_q = 0
25 # Override target().
26 global opt_child = 0
27
28 /* systemtap bug?  /usr/share/doc/systemtap-1.3/SystemTap_Beginners_Guide.pdf
29    Example 3.19 reads or writes?  */
30
31 global trace
32 global last_tid
33 probe begin
34 {
35   tid = opt_child > 0 ? opt_child : target ()
36   trace[tid] = 1
37   last_tid = tid
38 }
39
40 function heading (tid:long)
41 {
42   if (opt_ff)
43     return printf ("[%d]", tid)
44
45   foreach (tidi in trace limit 2)
46     tid_count++
47
48   if (tid_count > 1)
49     {
50       /* strace really calls TID a "pid".  */
51       return printf ("[pid %5d] ", tid)
52     }
53 }
54
55 global funcname
56 global nest
57
58 function realnl ()
59 {
60   if (opt_ff)
61     print ("n\n")
62   else
63     print ("\n")
64 }
65
66 probe end
67 {
68   if (nest[last_tid])
69     {
70       printf (") = ? <tracer terminated>")
71       realnl ()
72     }
73   foreach (tid in nest)
74     if (tid != last_tid)
75       {
76         heading (tid)
77         printf ("<... %s resumed> ) = ? <tracer terminated>",
78                 funcname[tid] != "" ? funcname[tid] : "?");
79         realnl ()
80       }
81 }
82
83 /* BUG: sleeping function called from invalid context at kernel/mutex.c:94
84 %{static DEFINE_MUTEX (tracer_mutex);%}
85 function lock ()
86 %{
87   mutex_lock (&tracer_mutex);
88 %}
89 function unlock ()
90 %{
91   mutex_unlock (&tracer_mutex);
92 %}
93 */
94 global lockvar
95 function lock ()
96 {
97   lockvar++
98 }
99 function unlock ()
100 {
101   lockvar++
102 }
103
104 #probe kprocess.start
105 #{
106 #  trace[pid ()] = 1
107 #}
108 #probe kprocess.exit
109 #{
110 #  trace[pid ()] = 0
111 #}
112 probe kprocess.create
113 {
114   if (opt_f && trace[tid ()] != 0)
115     {
116       /* systemtap bug?  Why `new_pid' is provided but `new_tid' is not?  */
117       new_tid = task_tid (task)
118       trace[new_tid] = 1
119       if (!opt_q)
120         {
121           printf ("Process %d attached", new_tid);
122           realnl ()
123         }
124     }
125 }
126
127 probe kprocess.release
128 {
129   /* systemtap bug?  Why `pid' is provided but `tid' is not?  */
130   /* systemtap bug?  Why `[pt]id' is not called `released_[pt]id' to keep the
131      naming in sync with kprocess.create?  */
132   tid = task_tid (task)
133   if (trace[tid] != 0)
134     {
135       if (nest[tid])
136         {
137           heading (tid)
138           /* FIXME: Do not assume "exit" for the nested calls.  */
139           printf ("<... %s resumed> = ?",
140                   funcname[tid] != "" ? funcname[tid] : "exit")
141           realnl ()
142           delete nest[tid]
143           delete funcname[tid]
144         }
145       delete trace[tid]
146       if (!opt_q)
147         {
148           printf ("Process %d detached", tid);
149           realnl ()
150         }
151     }
152 }
153 probe syscall.*
154 {
155   if (trace[tid ()] != 0)
156     {
157       lock ()
158       /* Why is mmap() called recursively twice?  */
159       if (nest[last_tid])
160         {
161           if (last_tid != tid ())
162             {
163               if (opt_ff)
164                 print ("c\n")
165               else
166                 print (" <unfinished ...>\n")
167             }
168           else
169             {
170               print (" <unfinished ...>")
171               realnl ()
172             }
173         }
174       last_tid = tid ();
175       funcname[tid ()] = name
176       nest[tid ()]++
177       heading (tid ())
178       printf ("%s(%s",name, argstr)
179       unlock ()
180     }
181 }
182 probe syscall.*.return
183 {
184   if (trace[tid ()] != 0)
185     {
186       lock ()
187       if (last_tid != tid () && nest[last_tid])
188         {
189           if (opt_ff)
190             print ("c\n")
191           else
192             print (" <unfinished ...>\n")
193         }
194       if (last_tid != tid ())
195         {
196           heading (tid ())
197           if (!opt_ff)
198             printf ("<... %s resumed> ", name);
199         }
200       if (last_tid == tid () && funcname[last_tid] == "")
201         {
202           heading (tid ())
203           printf ("<... %s resumed> ", name);
204         }
205       last_tid = tid ();
206       printf (") = %s", retstr)
207       realnl ()
208       if (!--nest[tid ()])
209         delete nest[tid ()]
210       delete funcname[tid ()]
211       unlock ()
212     }
213 }