24e77757192512d8066062111461c1155217d579
[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 global opt_f = 0
20 global opt_q = 0
21 # Override target().
22 global opt_child = 0
23
24 /* systemtap bug?  /usr/share/doc/systemtap-1.3/SystemTap_Beginners_Guide.pdf
25    Example 3.19 reads or writes?  */
26
27 global trace
28 global last_tid
29 probe begin
30 {
31   tid = opt_child > 0 ? opt_child : target ()
32   trace[tid] = 1
33   last_tid = tid
34 }
35
36 function heading:string (tid:long)
37 {
38   foreach (tidi in trace limit 2)
39     tid_count++
40
41   if (tid_count > 1)
42     {
43       /* strace really calls TID a "pid".  */
44       return sprintf ("[pid %5d] ", tid)
45     }
46   else
47     return ""
48 }
49
50 global funcname
51 global nest
52
53 probe end
54 {
55   if (nest[last_tid])
56     printf (") = ? <tracer terminated>\n")
57   foreach (tid in nest)
58     if (tid != last_tid)
59       printf ("%s<... %s resumed> ) = ? <tracer terminated>\n", heading (tid),
60               funcname[tid] != "" ? funcname[tid] : "?");
61 }
62
63 /* BUG: sleeping function called from invalid context at kernel/mutex.c:94
64 %{static DEFINE_MUTEX (tracer_mutex);%}
65 function lock ()
66 %{
67   mutex_lock (&tracer_mutex);
68 %}
69 function unlock ()
70 %{
71   mutex_unlock (&tracer_mutex);
72 %}
73 */
74 global lockvar
75 function lock ()
76 {
77   lockvar++
78 }
79 function unlock ()
80 {
81   lockvar++
82 }
83
84 #probe kprocess.start
85 #{
86 #  trace[pid ()] = 1
87 #}
88 #probe kprocess.exit
89 #{
90 #  trace[pid ()] = 0
91 #}
92 probe kprocess.create
93 {
94   if (opt_f && trace[tid ()] != 0)
95     {
96       /* systemtap bug?  Why `new_pid' is provided but `new_tid' is not?  */
97       new_tid = task_tid (task)
98       trace[new_tid] = 1
99       if (!opt_q)
100         printf ("Process %d attached\n", new_tid);
101     }
102 }
103
104 probe kprocess.release
105 {
106   /* systemtap bug?  Why `pid' is provided but `tid' is not?  */
107   /* systemtap bug?  Why `[pt]id' is not called `released_[pt]id' to keep the
108      naming in sync with kprocess.create?  */
109   tid = task_tid (task)
110   if (trace[tid] != 0)
111     {
112       if (nest[tid])
113         {
114           /* FIXME: Do not assume "exit" for the nested calls.  */
115           printf ("%s<... %s resumed> = ?\n", heading (tid),
116                   funcname[tid] != "" ? funcname[tid] : "exit")
117           delete nest[tid]
118           delete funcname[tid]
119         }
120       delete trace[tid]
121       if (!opt_q)
122         printf ("Process %d detached\n", tid);
123     }
124 }
125 probe syscall.*
126 {
127   if (trace[tid ()] != 0)
128     {
129       lock ()
130       /* Why is mmap() called recursively twice?  */
131       if (nest[last_tid])
132         printf (" <unfinished ...>\n")
133       last_tid = tid ();
134       funcname[tid ()] = name
135       nest[tid ()]++
136       printf ("%s%s(%s", heading (tid ()), name, argstr)
137       unlock ()
138     }
139 }
140 probe syscall.*.return
141 {
142   if (trace[tid ()] != 0)
143     {
144       lock ()
145       if (last_tid != tid () && nest[last_tid])
146         printf (" <unfinished ...>\n")
147       if (last_tid != tid () || (last_tid == tid () && !nest[last_tid]))
148         printf ("%s<... %s resumed> ", heading (tid ()), name);
149       last_tid = tid ();
150       printf (") = %s\n", retstr)
151       if (!--nest[tid ()])
152         delete nest[tid ()]
153       delete funcname[tid ()]
154       unlock ()
155     }
156 }