]> git.proxmox.com Git - qemu.git/blob - tracetool
Add a DTrace tracing backend targetted for SystemTAP compatability
[qemu.git] / tracetool
1 #!/bin/sh
2 #
3 # Code generator for trace events
4 #
5 # Copyright IBM, Corp. 2010
6 #
7 # This work is licensed under the terms of the GNU GPL, version 2. See
8 # the COPYING file in the top-level directory.
9
10 # Disable pathname expansion, makes processing text with '*' characters simpler
11 set -f
12
13 usage()
14 {
15 cat >&2 <<EOF
16 usage: $0 [--nop | --simple | --ust] [-h | -c]
17 Generate tracing code for a file on stdin.
18
19 Backends:
20 --nop Tracing disabled
21 --simple Simple built-in backend
22 --ust LTTng User Space Tracing backend
23 --dtrace DTrace/SystemTAP backend
24
25 Output formats:
26 -h Generate .h file
27 -c Generate .c file
28 -d Generate .d file (DTrace only)
29 EOF
30 exit 1
31 }
32
33 # Get the name of a trace event
34 get_name()
35 {
36 echo ${1%%\(*}
37 }
38
39 # Get the argument list of a trace event, including types and names
40 get_args()
41 {
42 local args
43 args=${1#*\(}
44 args=${args%\)*}
45 echo "$args"
46 }
47
48 # Get the argument name list of a trace event
49 get_argnames()
50 {
51 local nfields field name sep
52 nfields=0
53 sep="$2"
54 for field in $(get_args "$1"); do
55 nfields=$((nfields + 1))
56
57 # Drop pointer star
58 field=${field#\*}
59
60 # Only argument names have commas at the end
61 name=${field%,}
62 test "$field" = "$name" && continue
63
64 printf "%s%s " $name $sep
65 done
66
67 # Last argument name
68 if [ "$nfields" -gt 1 ]
69 then
70 printf "%s" "$name"
71 fi
72 }
73
74 # Get the number of arguments to a trace event
75 get_argc()
76 {
77 local name argc
78 argc=0
79 for name in $(get_argnames "$1", ","); do
80 argc=$((argc + 1))
81 done
82 echo $argc
83 }
84
85 # Get the format string for a trace event
86 get_fmt()
87 {
88 local fmt
89 fmt=${1#*\"}
90 fmt=${fmt%\"*}
91 echo "$fmt"
92 }
93
94 # Get the state of a trace event
95 get_state()
96 {
97 local str disable state
98 str=$(get_name "$1")
99 disable=${str##disable }
100 if [ "$disable" = "$str" ] ; then
101 state=1
102 else
103 state=0
104 fi
105 echo "$state"
106 }
107
108 linetoh_begin_nop()
109 {
110 return
111 }
112
113 linetoh_nop()
114 {
115 local name args
116 name=$(get_name "$1")
117 args=$(get_args "$1")
118
119 # Define an empty function for the trace event
120 cat <<EOF
121 static inline void trace_$name($args)
122 {
123 }
124 EOF
125 }
126
127 linetoh_end_nop()
128 {
129 return
130 }
131
132 linetoc_begin_nop()
133 {
134 return
135 }
136
137 linetoc_nop()
138 {
139 # No need for function definitions in nop backend
140 return
141 }
142
143 linetoc_end_nop()
144 {
145 return
146 }
147
148 linetoh_begin_simple()
149 {
150 cat <<EOF
151 #include "simpletrace.h"
152 EOF
153
154 simple_event_num=0
155 }
156
157 cast_args_to_uint64_t()
158 {
159 local arg
160 for arg in $(get_argnames "$1", ","); do
161 printf "%s" "(uint64_t)(uintptr_t)$arg"
162 done
163 }
164
165 linetoh_simple()
166 {
167 local name args argc trace_args state
168 name=$(get_name "$1")
169 args=$(get_args "$1")
170 argc=$(get_argc "$1")
171 state=$(get_state "$1")
172 if [ "$state" = "0" ]; then
173 name=${name##disable }
174 fi
175
176 trace_args="$simple_event_num"
177 if [ "$argc" -gt 0 ]
178 then
179 trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
180 fi
181
182 cat <<EOF
183 static inline void trace_$name($args)
184 {
185 trace$argc($trace_args);
186 }
187 EOF
188
189 simple_event_num=$((simple_event_num + 1))
190 }
191
192 linetoh_end_simple()
193 {
194 cat <<EOF
195 #define NR_TRACE_EVENTS $simple_event_num
196 extern TraceEvent trace_list[NR_TRACE_EVENTS];
197 EOF
198 }
199
200 linetoc_begin_simple()
201 {
202 cat <<EOF
203 #include "trace.h"
204
205 TraceEvent trace_list[] = {
206 EOF
207 simple_event_num=0
208
209 }
210
211 linetoc_simple()
212 {
213 local name state
214 name=$(get_name "$1")
215 state=$(get_state "$1")
216 if [ "$state" = "0" ] ; then
217 name=${name##disable }
218 fi
219 cat <<EOF
220 {.tp_name = "$name", .state=$state},
221 EOF
222 simple_event_num=$((simple_event_num + 1))
223 }
224
225 linetoc_end_simple()
226 {
227 cat <<EOF
228 };
229 EOF
230 }
231
232 # Clean up after UST headers which pollute the namespace
233 ust_clean_namespace() {
234 cat <<EOF
235 #undef mutex_lock
236 #undef mutex_unlock
237 #undef inline
238 #undef wmb
239 EOF
240 }
241
242 linetoh_begin_ust()
243 {
244 echo "#include <ust/tracepoint.h>"
245 ust_clean_namespace
246 }
247
248 linetoh_ust()
249 {
250 local name args argnames
251 name=$(get_name "$1")
252 args=$(get_args "$1")
253 argnames=$(get_argnames "$1", ",")
254
255 cat <<EOF
256 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
257 #define trace_$name trace_ust_$name
258 EOF
259 }
260
261 linetoh_end_ust()
262 {
263 return
264 }
265
266 linetoc_begin_ust()
267 {
268 cat <<EOF
269 #include <ust/marker.h>
270 $(ust_clean_namespace)
271 #include "trace.h"
272 EOF
273 }
274
275 linetoc_ust()
276 {
277 local name args argnames fmt
278 name=$(get_name "$1")
279 args=$(get_args "$1")
280 argnames=$(get_argnames "$1", ",")
281 fmt=$(get_fmt "$1")
282
283 cat <<EOF
284 DEFINE_TRACE(ust_$name);
285
286 static void ust_${name}_probe($args)
287 {
288 trace_mark(ust, $name, "$fmt", $argnames);
289 }
290 EOF
291
292 # Collect names for later
293 names="$names $name"
294 }
295
296 linetoc_end_ust()
297 {
298 cat <<EOF
299 static void __attribute__((constructor)) trace_init(void)
300 {
301 EOF
302
303 for name in $names; do
304 cat <<EOF
305 register_trace_ust_$name(ust_${name}_probe);
306 EOF
307 done
308
309 echo "}"
310 }
311
312 linetoh_begin_dtrace()
313 {
314 cat <<EOF
315 #include "trace-dtrace.h"
316 EOF
317 }
318
319 linetoh_dtrace()
320 {
321 local name args argnames state nameupper
322 name=$(get_name "$1")
323 args=$(get_args "$1")
324 argnames=$(get_argnames "$1", ",")
325 state=$(get_state "$1")
326 if [ "$state" = "0" ] ; then
327 name=${name##disable }
328 fi
329
330 nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
331
332 # Define an empty function for the trace event
333 cat <<EOF
334 static inline void trace_$name($args) {
335 if (QEMU_${nameupper}_ENABLED()) {
336 QEMU_${nameupper}($argnames);
337 }
338 }
339 EOF
340 }
341
342 linetoh_end_dtrace()
343 {
344 return
345 }
346
347 linetoc_begin_dtrace()
348 {
349 return
350 }
351
352 linetoc_dtrace()
353 {
354 # No need for function definitions in dtrace backend
355 return
356 }
357
358 linetoc_end_dtrace()
359 {
360 return
361 }
362
363 linetod_begin_dtrace()
364 {
365 cat <<EOF
366 provider qemu {
367 EOF
368 }
369
370 linetod_dtrace()
371 {
372 local name args state
373 name=$(get_name "$1")
374 args=$(get_args "$1")
375 state=$(get_state "$1")
376 if [ "$state" = "0" ] ; then
377 name=${name##disable }
378 fi
379
380 # Define prototype for probe arguments
381 cat <<EOF
382 probe $name($args);
383 EOF
384 }
385
386 linetod_end_dtrace()
387 {
388 cat <<EOF
389 };
390 EOF
391 }
392
393 # Process stdin by calling begin, line, and end functions for the backend
394 convert()
395 {
396 local begin process_line end str disable
397 begin="lineto$1_begin_$backend"
398 process_line="lineto$1_$backend"
399 end="lineto$1_end_$backend"
400
401 "$begin"
402
403 while read -r str; do
404 # Skip comments and empty lines
405 test -z "${str%%#*}" && continue
406
407 # Process the line. The nop backend handles disabled lines.
408 disable=${str%%disable *}
409 echo
410 if test -z "$disable"; then
411 # Pass the disabled state as an arg for the simple
412 # or DTrace backends which handle it dynamically.
413 # For all other backends, call lineto$1_nop()
414 if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
415 "$process_line" "$str"
416 else
417 "lineto$1_nop" "${str##disable }"
418 fi
419 else
420 "$process_line" "$str"
421 fi
422 done
423
424 echo
425 "$end"
426 }
427
428 tracetoh()
429 {
430 cat <<EOF
431 #ifndef TRACE_H
432 #define TRACE_H
433
434 /* This file is autogenerated by tracetool, do not edit. */
435
436 #include "qemu-common.h"
437 EOF
438 convert h
439 echo "#endif /* TRACE_H */"
440 }
441
442 tracetoc()
443 {
444 echo "/* This file is autogenerated by tracetool, do not edit. */"
445 convert c
446 }
447
448 tracetod()
449 {
450 if [ $backend != "dtrace" ]; then
451 echo "DTrace probe generator not applicable to $backend backend"
452 exit 1
453 fi
454 echo "/* This file is autogenerated by tracetool, do not edit. */"
455 convert d
456 }
457
458 # Choose backend
459 case "$1" in
460 "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
461 *) usage ;;
462 esac
463 shift
464
465 case "$1" in
466 "-h") tracetoh ;;
467 "-c") tracetoc ;;
468 "-d") tracetod ;;
469 "--check-backend") exit 0 ;; # used by ./configure to test for backend
470 *) usage ;;
471 esac
472
473 exit 0