Statistics
| Branch: | Revision:

root / tracetool @ 2834c3e0

History | View | Annotate | Download (9.2 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
  -s    Generate .stp file (DTrace with SystemTAP only)
30

    
31
Options:
32
  --bindir [bindir]  QEMU binary install location
33
  --target [arch]    QEMU target architecture
34

    
35
EOF
36
    exit 1
37
}
38

    
39
# Get the name of a trace event
40
get_name()
41
{
42
    echo ${1%%\(*}
43
}
44

    
45
# Get the argument list of a trace event, including types and names
46
get_args()
47
{
48
    local args
49
    args=${1#*\(}
50
    args=${args%\)*}
51
    echo "$args"
52
}
53

    
54
# Get the argument name list of a trace event
55
get_argnames()
56
{
57
    local nfields field name sep
58
    nfields=0
59
    sep="$2"
60
    for field in $(get_args "$1"); do
61
        nfields=$((nfields + 1))
62

    
63
        # Drop pointer star
64
        field=${field#\*}
65

    
66
        # Only argument names have commas at the end
67
        name=${field%,}
68
        test "$field" = "$name" && continue
69

    
70
        printf "%s%s " $name $sep
71
    done
72

    
73
    # Last argument name
74
    if [ "$nfields" -gt 1 ]
75
    then
76
        printf "%s" "$name"
77
    fi
78
}
79

    
80
# Get the number of arguments to a trace event
81
get_argc()
82
{
83
    local name argc
84
    argc=0
85
    for name in $(get_argnames "$1", ","); do
86
        argc=$((argc + 1))
87
    done
88
    echo $argc
89
}
90

    
91
# Get the format string for a trace event
92
get_fmt()
93
{
94
    local fmt
95
    fmt=${1#*\"}
96
    fmt=${fmt%\"*}
97
    echo "$fmt"
98
}
99

    
100
# Get the state of a trace event
101
get_state()
102
{
103
    local str disable state
104
    str=$(get_name "$1")
105
    disable=${str##disable }
106
    if [ "$disable" = "$str" ] ; then
107
        state=1
108
    else
109
        state=0
110
    fi
111
    echo "$state"
112
}
113

    
114
linetoh_begin_nop()
115
{
116
    return
117
}
118

    
119
linetoh_nop()
120
{
121
    local name args
122
    name=$(get_name "$1")
123
    args=$(get_args "$1")
124

    
125
    # Define an empty function for the trace event
126
    cat <<EOF
127
static inline void trace_$name($args)
128
{
129
}
130
EOF
131
}
132

    
133
linetoh_end_nop()
134
{
135
    return
136
}
137

    
138
linetoc_begin_nop()
139
{
140
    return
141
}
142

    
143
linetoc_nop()
144
{
145
    # No need for function definitions in nop backend
146
    return
147
}
148

    
149
linetoc_end_nop()
150
{
151
    return
152
}
153

    
154
linetoh_begin_simple()
155
{
156
    cat <<EOF
157
#include "simpletrace.h"
158
EOF
159

    
160
    simple_event_num=0
161
}
162

    
163
cast_args_to_uint64_t()
164
{
165
    local arg
166
    for arg in $(get_argnames "$1", ","); do
167
        printf "%s" "(uint64_t)(uintptr_t)$arg"
168
    done
169
}
170

    
171
linetoh_simple()
172
{
173
    local name args argc trace_args state
174
    name=$(get_name "$1")
175
    args=$(get_args "$1")
176
    argc=$(get_argc "$1")
177
    state=$(get_state "$1")
178
    if [ "$state" = "0" ]; then
179
        name=${name##disable }
180
    fi
181

    
182
    trace_args="$simple_event_num"
183
    if [ "$argc" -gt 0 ]
184
    then
185
        trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
186
    fi
187

    
188
    cat <<EOF
189
static inline void trace_$name($args)
190
{
191
    trace$argc($trace_args);
192
}
193
EOF
194

    
195
    simple_event_num=$((simple_event_num + 1))
196
}
197

    
198
linetoh_end_simple()
199
{
200
    cat <<EOF
201
#define NR_TRACE_EVENTS $simple_event_num
202
extern TraceEvent trace_list[NR_TRACE_EVENTS];
203
EOF
204
}
205

    
206
linetoc_begin_simple()
207
{
208
    cat <<EOF
209
#include "trace.h"
210

    
211
TraceEvent trace_list[] = {
212
EOF
213
    simple_event_num=0
214

    
215
}
216

    
217
linetoc_simple()
218
{
219
    local name state
220
    name=$(get_name "$1")
221
    state=$(get_state "$1")
222
    if [ "$state" = "0" ] ; then
223
        name=${name##disable }
224
    fi
225
    cat <<EOF
226
{.tp_name = "$name", .state=$state},
227
EOF
228
    simple_event_num=$((simple_event_num + 1))
229
}
230

    
231
linetoc_end_simple()
232
{
233
    cat <<EOF
234
};
235
EOF
236
}
237

    
238
# Clean up after UST headers which pollute the namespace
239
ust_clean_namespace() {
240
    cat <<EOF
241
#undef mutex_lock
242
#undef mutex_unlock
243
#undef inline
244
#undef wmb
245
EOF
246
}
247

    
248
linetoh_begin_ust()
249
{
250
    echo "#include <ust/tracepoint.h>"
251
    ust_clean_namespace
252
}
253

    
254
linetoh_ust()
255
{
256
    local name args argnames
257
    name=$(get_name "$1")
258
    args=$(get_args "$1")
259
    argnames=$(get_argnames "$1", ",")
260

    
261
    cat <<EOF
262
DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
263
#define trace_$name trace_ust_$name
264
EOF
265
}
266

    
267
linetoh_end_ust()
268
{
269
    return
270
}
271

    
272
linetoc_begin_ust()
273
{
274
    cat <<EOF
275
#include <ust/marker.h>
276
$(ust_clean_namespace)
277
#include "trace.h"
278
EOF
279
}
280

    
281
linetoc_ust()
282
{
283
    local name args argnames fmt
284
    name=$(get_name "$1")
285
    args=$(get_args "$1")
286
    argnames=$(get_argnames "$1", ",")
287
    fmt=$(get_fmt "$1")
288

    
289
    cat <<EOF
290
DEFINE_TRACE(ust_$name);
291

    
292
static void ust_${name}_probe($args)
293
{
294
    trace_mark(ust, $name, "$fmt", $argnames);
295
}
296
EOF
297

    
298
    # Collect names for later
299
    names="$names $name"
300
}
301

    
302
linetoc_end_ust()
303
{
304
    cat <<EOF
305
static void __attribute__((constructor)) trace_init(void)
306
{
307
EOF
308

    
309
    for name in $names; do
310
        cat <<EOF
311
    register_trace_ust_$name(ust_${name}_probe);
312
EOF
313
    done
314

    
315
    echo "}"
316
}
317

    
318
linetoh_begin_dtrace()
319
{
320
    cat <<EOF
321
#include "trace-dtrace.h"
322
EOF
323
}
324

    
325
linetoh_dtrace()
326
{
327
    local name args argnames state nameupper
328
    name=$(get_name "$1")
329
    args=$(get_args "$1")
330
    argnames=$(get_argnames "$1", ",")
331
    state=$(get_state "$1")
332
    if [ "$state" = "0" ] ; then
333
        name=${name##disable }
334
    fi
335

    
336
    nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
337

    
338
    # Define an empty function for the trace event
339
    cat <<EOF
340
static inline void trace_$name($args) {
341
    if (QEMU_${nameupper}_ENABLED()) {
342
        QEMU_${nameupper}($argnames);
343
    }
344
}
345
EOF
346
}
347

    
348
linetoh_end_dtrace()
349
{
350
    return
351
}
352

    
353
linetoc_begin_dtrace()
354
{
355
    return
356
}
357

    
358
linetoc_dtrace()
359
{
360
    # No need for function definitions in dtrace backend
361
    return
362
}
363

    
364
linetoc_end_dtrace()
365
{
366
    return
367
}
368

    
369
linetod_begin_dtrace()
370
{
371
    cat <<EOF
372
provider qemu {
373
EOF
374
}
375

    
376
linetod_dtrace()
377
{
378
    local name args state
379
    name=$(get_name "$1")
380
    args=$(get_args "$1")
381
    state=$(get_state "$1")
382
    if [ "$state" = "0" ] ; then
383
        name=${name##disable }
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
linetos_begin_dtrace()
400
{
401
    return
402
}
403

    
404
linetos_dtrace()
405
{
406
    local name args arglist state
407
    name=$(get_name "$1")
408
    args=$(get_args "$1")
409
    arglist=$(get_argnames "$1", "")
410
    state=$(get_state "$1")
411
    if [ "$state" = "0" ] ; then
412
        name=${name##disable }
413
    fi
414

    
415
    if [ "$target" = "i386" ]
416
    then
417
      binary="qemu"
418
    else
419
      binary="qemu-system-$target"
420
    fi
421

    
422
    # Define prototype for probe arguments
423
    cat <<EOF
424
probe qemu.system.$target.$name = process("$bindir/$binary").mark("$name")
425
{
426
EOF
427

    
428
    i=1
429
    for arg in $arglist
430
    do
431
        cat <<EOF
432
  $arg = \$arg$i;
433
EOF
434
	i="$((i+1))"
435
    done
436

    
437
    cat <<EOF
438
}
439
EOF
440
}
441

    
442
linetos_end_dtrace()
443
{
444
    return
445
}
446

    
447
# Process stdin by calling begin, line, and end functions for the backend
448
convert()
449
{
450
    local begin process_line end str disable
451
    begin="lineto$1_begin_$backend"
452
    process_line="lineto$1_$backend"
453
    end="lineto$1_end_$backend"
454

    
455
    "$begin"
456

    
457
    while read -r str; do
458
        # Skip comments and empty lines
459
        test -z "${str%%#*}" && continue
460

    
461
        # Process the line.  The nop backend handles disabled lines.
462
        disable=${str%%disable *}
463
        echo
464
        if test -z "$disable"; then
465
            # Pass the disabled state as an arg for the simple
466
            # or DTrace backends which handle it dynamically.
467
            # For all other backends, call lineto$1_nop()
468
            if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
469
                "$process_line" "$str"
470
            else
471
                "lineto$1_nop" "${str##disable }"
472
            fi
473
        else
474
            "$process_line" "$str"
475
        fi
476
    done
477

    
478
    echo
479
    "$end"
480
}
481

    
482
tracetoh()
483
{
484
    cat <<EOF
485
#ifndef TRACE_H
486
#define TRACE_H
487

    
488
/* This file is autogenerated by tracetool, do not edit. */
489

    
490
#include "qemu-common.h"
491
EOF
492
    convert h
493
    echo "#endif /* TRACE_H */"
494
}
495

    
496
tracetoc()
497
{
498
    echo "/* This file is autogenerated by tracetool, do not edit. */"
499
    convert c
500
}
501

    
502
tracetod()
503
{
504
    if [ $backend != "dtrace" ]; then
505
       echo "DTrace probe generator not applicable to $backend backend"
506
       exit 1
507
    fi
508
    echo "/* This file is autogenerated by tracetool, do not edit. */"
509
    convert d
510
}
511

    
512
tracetos()
513
{
514
    if [ $backend != "dtrace" ]; then
515
       echo "SystemTAP tapset generator not applicable to $backend backend"
516
       exit 1
517
    fi
518
    if [ -z "$target" ]; then
519
       echo "--target is required for SystemTAP tapset generator"
520
       exit 1
521
    fi
522
    if [ -z "$bindir" ]; then
523
       echo "--bindir is required for SystemTAP tapset generator"
524
       exit 1
525
    fi
526
    echo "/* This file is autogenerated by tracetool, do not edit. */"
527
    convert s
528
}
529

    
530
# Choose backend
531
case "$1" in
532
"--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
533
*) usage ;;
534
esac
535
shift
536

    
537
bindir=
538
case "$1" in
539
  "--bindir")
540
    bindir=$2
541
    shift
542
    shift
543
    ;;
544
esac
545

    
546
target=
547
case "$1" in
548
  "--target")
549
    target=$2
550
    shift
551
    shift
552
    ;;
553
esac
554

    
555

    
556
case "$1" in
557
"-h") tracetoh ;;
558
"-c") tracetoc ;;
559
"-d") tracetod ;;
560
"-s") tracetos ;;
561
"--check-backend") exit 0 ;; # used by ./configure to test for backend
562
*) usage ;;
563
esac
564

    
565
exit 0