Statistics
| Branch: | Revision:

root / tracetool @ b3d08c02

History | View | Annotate | Download (7.9 kB)

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
    # 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);
389
EOF
390
}
391

    
392
linetod_end_dtrace()
393
{
394
    cat <<EOF
395
};
396
EOF
397
}
398

    
399
# Process stdin by calling begin, line, and end functions for the backend
400
convert()
401
{
402
    local begin process_line end str disable
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
411
        test -z "${str%%#*}" && continue
412

    
413
        # Process the line.  The nop backend handles disabled lines.
414
        disable=${str%%disable *}
415
        echo
416
        if test -z "$disable"; then
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
421
                "$process_line" "$str"
422
            else
423
                "lineto$1_nop" "${str##disable }"
424
            fi
425
        else
426
            "$process_line" "$str"
427
        fi
428
    done
429

    
430
    echo
431
    "$end"
432
}
433

    
434
tracetoh()
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"
443
EOF
444
    convert h
445
    echo "#endif /* TRACE_H */"
446
}
447

    
448
tracetoc()
449
{
450
    echo "/* This file is autogenerated by tracetool, do not edit. */"
451
    convert c
452
}
453

    
454
tracetod()
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

    
464
# Choose backend
465
case "$1" in
466
"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
467
*) usage ;;
468
esac
469
shift
470

    
471
case "$1" in
472
"-h") tracetoh ;;
473
"-c") tracetoc ;;
474
"-d") tracetod ;;
475
"--check-backend") exit 0 ;; # used by ./configure to test for backend
476
*) usage ;;
477
esac
478

    
479
exit 0