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