]> git.proxmox.com Git - qemu.git/blob - scripts/tracetool
simpletrace: Make simpletrace.py a Python module
[qemu.git] / scripts / 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 | --stderr | --ust | --dtrace] [-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 --stderr Stderr built-in backend
23 --ust LTTng User Space Tracing backend
24 --dtrace DTrace/SystemTAP backend
25
26 Output formats:
27 -h Generate .h file
28 -c Generate .c file
29 -d Generate .d file (DTrace only)
30 --stap Generate .stp file (DTrace with SystemTAP only)
31
32 Options:
33 --binary [path] Full path to QEMU binary
34 --target-arch [arch] QEMU emulator target arch
35 --target-type [type] QEMU emulator target type ('system' or 'user')
36
37 EOF
38 exit 1
39 }
40
41 # Get the name of a trace event
42 get_name()
43 {
44 echo ${1%%\(*}
45 }
46
47 # Get the argument list of a trace event, including types and names
48 get_args()
49 {
50 local args
51 args=${1#*\(}
52 args=${args%\)*}
53 echo "$args"
54 }
55
56 # Get the argument name list of a trace event
57 get_argnames()
58 {
59 local nfields field name sep
60 nfields=0
61 sep="$2"
62 for field in $(get_args "$1"); do
63 nfields=$((nfields + 1))
64
65 # Drop pointer star
66 field=${field#\*}
67
68 # Only argument names have commas at the end
69 name=${field%,}
70 test "$field" = "$name" && continue
71
72 printf "%s%s " $name $sep
73 done
74
75 # Last argument name
76 if [ "$nfields" -gt 1 ]
77 then
78 printf "%s" "$name"
79 fi
80 }
81
82 # Get the number of arguments to a trace event
83 get_argc()
84 {
85 local name argc
86 argc=0
87 for name in $(get_argnames "$1", ","); do
88 argc=$((argc + 1))
89 done
90 echo $argc
91 }
92
93 # Get the format string for a trace event
94 get_fmt()
95 {
96 local fmt
97 fmt=${1#*\"}
98 fmt=${fmt%\"*}
99 echo "$fmt"
100 }
101
102 # Get the state of a trace event
103 get_state()
104 {
105 local str disable state
106 str=$(get_name "$1")
107 disable=${str##disable }
108 if [ "$disable" = "$str" ] ; then
109 state=1
110 else
111 state=0
112 fi
113 echo "$state"
114 }
115
116 linetoh_begin_nop()
117 {
118 return
119 }
120
121 linetoh_nop()
122 {
123 local name args
124 name=$(get_name "$1")
125 args=$(get_args "$1")
126
127 # Define an empty function for the trace event
128 cat <<EOF
129 static inline void trace_$name($args)
130 {
131 }
132 EOF
133 }
134
135 linetoh_end_nop()
136 {
137 return
138 }
139
140 linetoc_begin_nop()
141 {
142 return
143 }
144
145 linetoc_nop()
146 {
147 # No need for function definitions in nop backend
148 return
149 }
150
151 linetoc_end_nop()
152 {
153 return
154 }
155
156 linetoh_begin_simple()
157 {
158 cat <<EOF
159 #include "simpletrace.h"
160 EOF
161
162 simple_event_num=0
163 }
164
165 cast_args_to_uint64_t()
166 {
167 local arg
168 for arg in $(get_argnames "$1", ","); do
169 printf "%s" "(uint64_t)(uintptr_t)$arg"
170 done
171 }
172
173 linetoh_simple()
174 {
175 local name args argc trace_args state
176 name=$(get_name "$1")
177 args=$(get_args "$1")
178 argc=$(get_argc "$1")
179 state=$(get_state "$1")
180 if [ "$state" = "0" ]; then
181 name=${name##disable }
182 fi
183
184 trace_args="$simple_event_num"
185 if [ "$argc" -gt 0 ]
186 then
187 trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
188 fi
189
190 cat <<EOF
191 static inline void trace_$name($args)
192 {
193 trace$argc($trace_args);
194 }
195 EOF
196
197 simple_event_num=$((simple_event_num + 1))
198 }
199
200 linetoh_end_simple()
201 {
202 cat <<EOF
203 #define NR_TRACE_EVENTS $simple_event_num
204 extern TraceEvent trace_list[NR_TRACE_EVENTS];
205 EOF
206 }
207
208 linetoc_begin_simple()
209 {
210 cat <<EOF
211 #include "trace.h"
212
213 TraceEvent trace_list[] = {
214 EOF
215 simple_event_num=0
216
217 }
218
219 linetoc_simple()
220 {
221 local name state
222 name=$(get_name "$1")
223 state=$(get_state "$1")
224 if [ "$state" = "0" ] ; then
225 name=${name##disable }
226 fi
227 cat <<EOF
228 {.tp_name = "$name", .state=$state},
229 EOF
230 simple_event_num=$((simple_event_num + 1))
231 }
232
233 linetoc_end_simple()
234 {
235 cat <<EOF
236 };
237 EOF
238 }
239
240 #STDERR
241 linetoh_begin_stderr()
242 {
243 cat <<EOF
244 #include <stdio.h>
245 EOF
246 }
247
248 linetoh_stderr()
249 {
250 local name args argnames argc fmt
251 name=$(get_name "$1")
252 args=$(get_args "$1")
253 argnames=$(get_argnames "$1" ",")
254 argc=$(get_argc "$1")
255 fmt=$(get_fmt "$1")
256
257 if [ "$argc" -gt 0 ]; then
258 argnames=", $argnames"
259 fi
260
261 cat <<EOF
262 static inline void trace_$name($args)
263 {
264 fprintf(stderr, "$name $fmt\n" $argnames);
265 }
266 EOF
267 }
268
269 linetoh_end_stderr()
270 {
271 return
272 }
273
274 linetoc_begin_stderr()
275 {
276 return
277 }
278
279 linetoc_stderr()
280 {
281 return
282 }
283
284 linetoc_end_stderr()
285 {
286 return
287 }
288 #END OF STDERR
289
290 # Clean up after UST headers which pollute the namespace
291 ust_clean_namespace() {
292 cat <<EOF
293 #undef mutex_lock
294 #undef mutex_unlock
295 #undef inline
296 #undef wmb
297 EOF
298 }
299
300 linetoh_begin_ust()
301 {
302 echo "#include <ust/tracepoint.h>"
303 ust_clean_namespace
304 }
305
306 linetoh_ust()
307 {
308 local name args argnames
309 name=$(get_name "$1")
310 args=$(get_args "$1")
311 argnames=$(get_argnames "$1", ",")
312
313 cat <<EOF
314 DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
315 #define trace_$name trace_ust_$name
316 EOF
317 }
318
319 linetoh_end_ust()
320 {
321 return
322 }
323
324 linetoc_begin_ust()
325 {
326 cat <<EOF
327 #include <ust/marker.h>
328 $(ust_clean_namespace)
329 #include "trace.h"
330 EOF
331 }
332
333 linetoc_ust()
334 {
335 local name args argnames fmt
336 name=$(get_name "$1")
337 args=$(get_args "$1")
338 argnames=$(get_argnames "$1", ",")
339 fmt=$(get_fmt "$1")
340
341 cat <<EOF
342 DEFINE_TRACE(ust_$name);
343
344 static void ust_${name}_probe($args)
345 {
346 trace_mark(ust, $name, "$fmt", $argnames);
347 }
348 EOF
349
350 # Collect names for later
351 names="$names $name"
352 }
353
354 linetoc_end_ust()
355 {
356 cat <<EOF
357 static void __attribute__((constructor)) trace_init(void)
358 {
359 EOF
360
361 for name in $names; do
362 cat <<EOF
363 register_trace_ust_$name(ust_${name}_probe);
364 EOF
365 done
366
367 echo "}"
368 }
369
370 linetoh_begin_dtrace()
371 {
372 cat <<EOF
373 #include "trace-dtrace.h"
374 EOF
375 }
376
377 linetoh_dtrace()
378 {
379 local name args argnames state nameupper
380 name=$(get_name "$1")
381 args=$(get_args "$1")
382 argnames=$(get_argnames "$1", ",")
383 state=$(get_state "$1")
384 if [ "$state" = "0" ] ; then
385 name=${name##disable }
386 fi
387
388 nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
389
390 # Define an empty function for the trace event
391 cat <<EOF
392 static inline void trace_$name($args) {
393 if (QEMU_${nameupper}_ENABLED()) {
394 QEMU_${nameupper}($argnames);
395 }
396 }
397 EOF
398 }
399
400 linetoh_end_dtrace()
401 {
402 return
403 }
404
405 linetoc_begin_dtrace()
406 {
407 return
408 }
409
410 linetoc_dtrace()
411 {
412 # No need for function definitions in dtrace backend
413 return
414 }
415
416 linetoc_end_dtrace()
417 {
418 return
419 }
420
421 linetod_begin_dtrace()
422 {
423 cat <<EOF
424 provider qemu {
425 EOF
426 }
427
428 linetod_dtrace()
429 {
430 local name args state
431 name=$(get_name "$1")
432 args=$(get_args "$1")
433 state=$(get_state "$1")
434 if [ "$state" = "0" ] ; then
435 name=${name##disable }
436 fi
437
438 # DTrace provider syntax expects foo() for empty
439 # params, not foo(void)
440 if [ "$args" = "void" ]; then
441 args=""
442 fi
443
444 # Define prototype for probe arguments
445 cat <<EOF
446 probe $name($args);
447 EOF
448 }
449
450 linetod_end_dtrace()
451 {
452 cat <<EOF
453 };
454 EOF
455 }
456
457 linetostap_begin_dtrace()
458 {
459 return
460 }
461
462 linetostap_dtrace()
463 {
464 local i arg name args arglist state
465 name=$(get_name "$1")
466 args=$(get_args "$1")
467 arglist=$(get_argnames "$1", "")
468 state=$(get_state "$1")
469 if [ "$state" = "0" ] ; then
470 name=${name##disable }
471 fi
472
473 # Define prototype for probe arguments
474 cat <<EOF
475 probe qemu.$targettype.$targetarch.$name = process("$binary").mark("$name")
476 {
477 EOF
478
479 i=1
480 for arg in $arglist
481 do
482 # 'limit' is a reserved keyword
483 if [ "$arg" = "limit" ]; then
484 arg="_limit"
485 fi
486 cat <<EOF
487 $arg = \$arg$i;
488 EOF
489 i="$((i+1))"
490 done
491
492 cat <<EOF
493 }
494 EOF
495 }
496
497 linetostap_end_dtrace()
498 {
499 return
500 }
501
502 # Process stdin by calling begin, line, and end functions for the backend
503 convert()
504 {
505 local begin process_line end str disable
506 begin="lineto$1_begin_$backend"
507 process_line="lineto$1_$backend"
508 end="lineto$1_end_$backend"
509
510 "$begin"
511
512 while read -r str; do
513 # Skip comments and empty lines
514 test -z "${str%%#*}" && continue
515
516 # Process the line. The nop backend handles disabled lines.
517 disable=${str%%disable *}
518 echo
519 if test -z "$disable"; then
520 # Pass the disabled state as an arg for the simple
521 # or DTrace backends which handle it dynamically.
522 # For all other backends, call lineto$1_nop()
523 if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
524 "$process_line" "$str"
525 else
526 "lineto$1_nop" "${str##disable }"
527 fi
528 else
529 "$process_line" "$str"
530 fi
531 done
532
533 echo
534 "$end"
535 }
536
537 tracetoh()
538 {
539 cat <<EOF
540 #ifndef TRACE_H
541 #define TRACE_H
542
543 /* This file is autogenerated by tracetool, do not edit. */
544
545 #include "qemu-common.h"
546 EOF
547 convert h
548 echo "#endif /* TRACE_H */"
549 }
550
551 tracetoc()
552 {
553 echo "/* This file is autogenerated by tracetool, do not edit. */"
554 convert c
555 }
556
557 tracetod()
558 {
559 if [ $backend != "dtrace" ]; then
560 echo "DTrace probe generator not applicable to $backend backend"
561 exit 1
562 fi
563 echo "/* This file is autogenerated by tracetool, do not edit. */"
564 convert d
565 }
566
567 tracetostap()
568 {
569 if [ $backend != "dtrace" ]; then
570 echo "SystemTAP tapset generator not applicable to $backend backend"
571 exit 1
572 fi
573 if [ -z "$binary" ]; then
574 echo "--binary is required for SystemTAP tapset generator"
575 exit 1
576 fi
577 if [ -z "$targettype" ]; then
578 echo "--target-type is required for SystemTAP tapset generator"
579 exit 1
580 fi
581 if [ -z "$targetarch" ]; then
582 echo "--target-arch is required for SystemTAP tapset generator"
583 exit 1
584 fi
585 echo "/* This file is autogenerated by tracetool, do not edit. */"
586 convert stap
587 }
588
589
590 backend=
591 output=
592 binary=
593 targettype=
594 targetarch=
595
596
597 until [ -z "$1" ]
598 do
599 case "$1" in
600 "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
601
602 "--binary") shift ; binary="$1" ;;
603 "--target-arch") shift ; targetarch="$1" ;;
604 "--target-type") shift ; targettype="$1" ;;
605
606 "-h" | "-c" | "-d") output="${1#-}" ;;
607 "--stap") output="${1#--}" ;;
608
609 "--check-backend") exit 0 ;; # used by ./configure to test for backend
610
611 "--list-backends") # used by ./configure to list available backends
612 echo "nop simple stderr ust dtrace"
613 exit 0
614 ;;
615
616 *)
617 usage;;
618 esac
619 shift
620 done
621
622 if [ "$backend" = "" -o "$output" = "" ]; then
623 usage
624 fi
625
626 gen="traceto$output"
627 "$gen"
628
629 exit 0