-ff output coherency fixes.
[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] && funcname[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:long ()
86 %{
87   if (in_atomic () || irqs_disabled())
88     {
89       THIS->__retvalue = 0;
90       return;
91     }
92   mutex_lock (&tracer_mutex);
93   THIS->__retvalue = 1;
94 %}
95 function unlock ()
96 %{
97   mutex_unlock (&tracer_mutex);
98 %}
99 /*
100 # systamtap bug? on void function value use no warning is given.
101 global lockvar
102 function lock:long ()
103 {
104   lockvar++
105   return 1
106 }
107 function unlock ()
108 {
109   lockvar--
110 }
111 */
112
113 #probe kprocess.start
114 #{
115 #  trace[pid ()] = 1
116 #}
117 #probe kprocess.exit
118 #{
119 #  trace[pid ()] = 0
120 #}
121 probe kprocess.create
122 {
123   if (opt_f && trace[tid ()] != 0)
124     {
125       /* systemtap bug?  Why `new_pid' is provided but `new_tid' is not?  */
126       new_tid = task_tid (task)
127       trace[new_tid] = 1
128       if (!opt_q)
129         {
130           printf ("Process %d attached", new_tid);
131           realnl ()
132         }
133     }
134 }
135
136 probe kprocess.release
137 {
138   /* systemtap bug?  Why `pid' is provided but `tid' is not?  */
139   /* systemtap bug?  Why `[pt]id' is not called `released_[pt]id' to keep the
140      naming in sync with kprocess.create?  */
141   tid = task_tid (task)
142   if (trace[tid] != 0)
143     {
144       if (nest[tid])
145         {
146           heading (tid)
147           /* FIXME: Do not assume "exit" for the nested calls.  */
148           printf ("<... %s resumed> = ?",
149                   funcname[tid] != "" ? funcname[tid] : "exit")
150           realnl ()
151           delete nest[tid]
152           delete funcname[tid]
153         }
154       delete trace[tid]
155       if (!opt_q)
156         {
157           printf ("Process %d detached", tid);
158           realnl ()
159         }
160     }
161 }
162 probe syscall.*
163 {
164   if (trace[tid ()] != 0 && lock ())
165     {
166       /* Why is mmap() called recursively twice?  */
167       if (nest[last_tid] && funcname[last_tid] != "")
168         {
169           if (last_tid != tid ())
170             {
171               if (opt_ff)
172                 print ("c\n")
173               else
174                 print (" <unfinished ...>\n")
175             }
176           else
177             {
178               print (" <unfinished ...>")
179               realnl ()
180             }
181         }
182       last_tid = tid ();
183       funcname[tid ()] = name
184       nest[tid ()]++
185       heading (tid ())
186       printf ("%s(%s",name, argstr)
187       unlock ()
188     }
189 }
190 probe syscall.*.return
191 {
192   if (trace[tid ()] != 0 && lock ())
193     {
194       if (last_tid != tid () && nest[last_tid] && funcname[last_tid] != "")
195         {
196           if (opt_ff)
197             print ("c\n")
198           else
199             print (" <unfinished ...>\n")
200         }
201       if (last_tid != tid ())
202         {
203           heading (tid ())
204           if (!opt_ff)
205             printf ("<... %s resumed> ", name);
206         }
207       if (last_tid == tid () && funcname[last_tid] == "")
208         {
209           heading (tid ())
210           printf ("<... %s resumed> ", name);
211         }
212       last_tid = tid ();
213       printf (") = %s", retstr)
214       realnl ()
215       if (!--nest[tid ()])
216         delete nest[tid ()]
217       delete funcname[tid ()]
218       unlock ()
219     }
220 }