21111d6d9e36fed0b7d79f12daf3bff150ddbb71
[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 global trace
29 global last_tid
30 probe begin
31 {
32   tid = opt_child > 0 ? opt_child : target ()
33   trace[tid] = 1
34   last_tid = tid
35 }
36
37 function heading (tid:long)
38 {
39   if (opt_ff)
40     return printf ("[%d]", tid)
41
42   foreach (tidi in trace limit 2)
43     tid_count++
44
45   if (tid_count > 1)
46     {
47       /* strace really calls TID a "pid".  */
48       return printf ("[pid %5d] ", tid)
49     }
50 }
51
52 global funcname
53 global nest
54
55 function realnl ()
56 {
57   if (opt_ff)
58     print ("n\n")
59   else
60     print ("\n")
61 }
62
63 probe end
64 {
65   if (nest[last_tid] && funcname[last_tid] != "")
66     {
67       printf (") = ? <tracer terminated>")
68       realnl ()
69     }
70   foreach (tid in nest)
71     if (tid != last_tid)
72       {
73         heading (tid)
74         printf ("<... %s resumed> ) = ? <tracer terminated>",
75                 funcname[tid] != "" ? funcname[tid] : "?");
76         realnl ()
77       }
78 }
79
80 /* BUG: sleeping function called from invalid context at kernel/mutex.c:94  */
81 %{static DEFINE_MUTEX (tracer_mutex);%}
82 function lock:long ()
83 %{
84   if (in_atomic () || irqs_disabled())
85     {
86       THIS->__retvalue = 0;
87       return;
88     }
89   mutex_lock (&tracer_mutex);
90   THIS->__retvalue = 1;
91 %}
92 function unlock ()
93 %{
94   mutex_unlock (&tracer_mutex);
95 %}
96 /*
97 # systamtap bug? on void function value use no warning is given.
98 global lockvar
99 function lock:long ()
100 {
101   lockvar++
102   return 1
103 }
104 function unlock ()
105 {
106   lockvar--
107 }
108 */
109
110 #probe kprocess.start
111 #{
112 #  trace[pid ()] = 1
113 #}
114 #probe kprocess.exit
115 #{
116 #  trace[pid ()] = 0
117 #}
118 probe kprocess.create
119 {
120   if (opt_f && trace[tid ()] != 0)
121     {
122       /* systemtap bug?  Why `new_pid' is provided but `new_tid' is not?  */
123       new_tid = task_tid (task)
124       trace[new_tid] = 1
125       if (!opt_q)
126         {
127           printf ("Process %d attached", new_tid);
128           realnl ()
129         }
130     }
131 }
132
133 probe kprocess.release
134 {
135   /* systemtap bug?  Why `pid' is provided but `tid' is not?  */
136   /* systemtap bug?  Why `[pt]id' is not called `released_[pt]id' to keep the
137      naming in sync with kprocess.create?  */
138   tid = task_tid (task)
139   if (trace[tid] != 0)
140     {
141       if (nest[tid])
142         {
143           heading (tid)
144           /* FIXME: Do not assume "exit" for the nested calls.  */
145           printf ("<... %s resumed> = ?",
146                   funcname[tid] != "" ? funcname[tid] : "exit")
147           realnl ()
148           delete nest[tid]
149           delete funcname[tid]
150         }
151       delete trace[tid]
152       if (!opt_q)
153         {
154           printf ("Process %d detached", tid);
155           realnl ()
156         }
157     }
158 }
159 probe syscall.*
160 {
161   if (trace[tid ()] != 0 && lock ())
162     {
163       /* Why is mmap() called recursively twice?  */
164       if (nest[last_tid] && funcname[last_tid] != "")
165         {
166           if (last_tid != tid ())
167             {
168               if (opt_ff)
169                 print ("c\n")
170               else
171                 print (" <unfinished ...>\n")
172             }
173           else
174             {
175               print (" <unfinished ...>")
176               realnl ()
177             }
178         }
179       last_tid = tid ();
180       funcname[tid ()] = name
181       nest[tid ()]++
182       heading (tid ())
183       printf ("%s(%s",name, argstr)
184       unlock ()
185     }
186 }
187 probe syscall.*.return
188 {
189   if (trace[tid ()] != 0 && lock ())
190     {
191       if (last_tid != tid () && nest[last_tid] && funcname[last_tid] != "")
192         {
193           if (opt_ff)
194             print ("c\n")
195           else
196             print (" <unfinished ...>\n")
197         }
198       if (last_tid != tid ())
199         {
200           heading (tid ())
201           if (!opt_ff)
202             printf ("<... %s resumed> ", name);
203         }
204       if (last_tid == tid () && funcname[last_tid] == "")
205         {
206           heading (tid ())
207           printf ("<... %s resumed> ", name);
208         }
209       last_tid = tid ();
210       printf (") = %s", retstr)
211       realnl ()
212       if (!--nest[tid ()])
213         delete nest[tid ()]
214       delete funcname[tid ()]
215       unlock ()
216     }
217 }