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