Statistics
| Branch: | Revision:

root / tracetool @ c276b17d

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

    
31
Options:
32
  --binary      [path]  Full path to QEMU binary
33
  --target-arch [arch]  QEMU emulator target arch
34
  --target-type [type]  QEMU emulator target type ('system' or 'user')
35

    
36
EOF
37
    exit 1
38
}
39

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

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

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

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

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

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

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

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

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

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

    
115
linetoh_begin_nop()
116
{
117
    return
118
}
119

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

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

    
134
linetoh_end_nop()
135
{
136
    return
137
}
138

    
139
linetoc_begin_nop()
140
{
141
    return
142
}
143

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

    
150
linetoc_end_nop()
151
{
152
    return
153
}
154

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

    
161
    simple_event_num=0
162
}
163

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

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

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

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

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

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

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

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

    
216
}
217

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

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

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

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

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

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

    
268
linetoh_end_ust()
269
{
270
    return
271
}
272

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

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

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

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

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

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

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

    
316
    echo "}"
317
}
318

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

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

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

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

    
349
linetoh_end_dtrace()
350
{
351
    return
352
}
353

    
354
linetoc_begin_dtrace()
355
{
356
    return
357
}
358

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

    
365
linetoc_end_dtrace()
366
{
367
    return
368
}
369

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

    
377
linetod_dtrace()
378
{
379
    local name args state
380
    name=$(get_name "$1")
381
    args=$(get_args "$1")
382
    state=$(get_state "$1")
383
    if [ "$state" = "0" ] ; then
384
        name=${name##disable }
385
    fi
386

    
387
    # DTrace provider syntax expects foo() for empty
388
    # params, not foo(void)
389
    if [ "$args" = "void" ]; then
390
       args=""
391
    fi
392

    
393
    # Define prototype for probe arguments
394
    cat <<EOF
395
        probe $name($args);
396
EOF
397
}
398

    
399
linetod_end_dtrace()
400
{
401
    cat <<EOF
402
};
403
EOF
404
}
405

    
406
linetostap_begin_dtrace()
407
{
408
    return
409
}
410

    
411
linetostap_dtrace()
412
{
413
    local i arg name args arglist state
414
    name=$(get_name "$1")
415
    args=$(get_args "$1")
416
    arglist=$(get_argnames "$1", "")
417
    state=$(get_state "$1")
418
    if [ "$state" = "0" ] ; then
419
        name=${name##disable }
420
    fi
421

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

    
428
    i=1
429
    for arg in $arglist
430
    do
431
        # 'limit' is a reserved keyword
432
        if [ "$arg" = "limit" ]; then
433
          arg="_limit"
434
        fi
435
        cat <<EOF
436
  $arg = \$arg$i;
437
EOF
438
	i="$((i+1))"
439
    done
440

    
441
    cat <<EOF
442
}
443
EOF
444
}
445

    
446
linetostap_end_dtrace()
447
{
448
    return
449
}
450

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

    
459
    "$begin"
460

    
461
    while read -r str; do
462
        # Skip comments and empty lines
463
        test -z "${str%%#*}" && continue
464

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

    
482
    echo
483
    "$end"
484
}
485

    
486
tracetoh()
487
{
488
    cat <<EOF
489
#ifndef TRACE_H
490
#define TRACE_H
491

    
492
/* This file is autogenerated by tracetool, do not edit. */
493

    
494
#include "qemu-common.h"
495
EOF
496
    convert h
497
    echo "#endif /* TRACE_H */"
498
}
499

    
500
tracetoc()
501
{
502
    echo "/* This file is autogenerated by tracetool, do not edit. */"
503
    convert c
504
}
505

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

    
516
tracetostap()
517
{
518
    if [ $backend != "dtrace" ]; then
519
       echo "SystemTAP tapset generator not applicable to $backend backend"
520
       exit 1
521
    fi
522
    if [ -z "$binary" ]; then
523
       echo "--binary is required for SystemTAP tapset generator"
524
       exit 1
525
    fi
526
    if [ -z "$targettype" ]; then
527
       echo "--target-type is required for SystemTAP tapset generator"
528
       exit 1
529
    fi
530
    if [ -z "$targetarch" ]; then
531
       echo "--target-arch is required for SystemTAP tapset generator"
532
       exit 1
533
    fi
534
    echo "/* This file is autogenerated by tracetool, do not edit. */"
535
    convert stap
536
}
537

    
538

    
539
backend=
540
output=
541
binary=
542
targettype=
543
targetarch=
544

    
545

    
546
until [ -z "$1" ]
547
do
548
  case "$1" in
549
    "--nop" | "--simple" | "--ust" | "--dtrace") backend="${1#--}" ;;
550

    
551
    "--binary") shift ; binary="$1" ;;
552
    "--target-arch") shift ; targetarch="$1" ;;
553
    "--target-type") shift ; targettype="$1" ;;
554

    
555
    "-h" | "-c" | "-d") output="${1#-}" ;;
556
    "--stap") output="${1#--}" ;;
557

    
558
    "--check-backend") exit 0 ;; # used by ./configure to test for backend
559

    
560
    *)
561
      usage;;
562
  esac
563
  shift
564
done
565

    
566
if [ "$backend" = "" -o "$output" = "" ]; then
567
  usage
568
fi
569

    
570
gen="traceto$output"
571
"$gen"
572

    
573
exit 0