xref: /openbmc/qemu/scripts/tracetool/format/log_stap.py (revision 9f4e519fd7acbdb027d22e13e4f1cd8e79969dec)
1# -*- coding: utf-8 -*-
2
3"""
4Generate .stp file that printfs log messages (DTrace with SystemTAP only).
5"""
6
7__author__     = "Daniel P. Berrange <berrange@redhat.com>"
8__copyright__  = "Copyright (C) 2014-2019, Red Hat, Inc."
9__license__    = "GPL version 2 or (at your option) any later version"
10
11__maintainer__ = "Daniel Berrange"
12__email__      = "berrange@redhat.com"
13
14import re
15
16from tracetool import out
17from tracetool.backend.dtrace import binary, probeprefix
18from tracetool.backend.simple import is_string
19from tracetool.format.stap import stap_escape
20
21def global_var_name(name):
22    return probeprefix().replace(".", "_") + "_" + name
23
24STATE_SKIP = 0
25STATE_LITERAL = 1
26STATE_MACRO = 2
27
28def c_macro_to_format(macro):
29    if macro.startswith("PRI"):
30        return macro[3]
31
32    raise Exception("Unhandled macro '%s'" % macro)
33
34def c_fmt_to_stap(fmt):
35    state = 0
36    bits = []
37    literal = ""
38    macro = ""
39    escape = 0;
40    for i in range(len(fmt)):
41        if fmt[i] == '\\':
42            if escape:
43                escape = 0
44            else:
45                escape = 1
46            if state != STATE_LITERAL:
47                raise Exception("Unexpected escape outside string literal")
48            literal = literal + fmt[i]
49        elif fmt[i] == '"' and not escape:
50            if state == STATE_LITERAL:
51                state = STATE_SKIP
52                bits.append(literal)
53                literal = ""
54            else:
55                if state == STATE_MACRO:
56                    bits.append(c_macro_to_format(macro))
57                    macro = ""
58                state = STATE_LITERAL
59        elif fmt[i] == ' ' or fmt[i] == '\t':
60            if state == STATE_MACRO:
61                bits.append(c_macro_to_format(macro))
62                macro = ""
63                state = STATE_SKIP
64            elif state == STATE_LITERAL:
65                literal = literal + fmt[i]
66        else:
67            escape = 0
68            if state == STATE_SKIP:
69                state = STATE_MACRO
70
71            if state == STATE_LITERAL:
72                literal = literal + fmt[i]
73            else:
74                macro = macro + fmt[i]
75
76    if state == STATE_MACRO:
77        bits.append(c_macro_to_format(macro))
78    elif state == STATE_LITERAL:
79        bits.append(literal)
80
81    fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".join(bits))
82    return fmt
83
84def generate(events, backend, group):
85    out('/* This file is autogenerated by tracetool, do not edit. */',
86        '')
87
88    for event_id, e in enumerate(events):
89        if 'disable' in e.properties:
90            continue
91
92        out('probe %(probeprefix)s.log.%(name)s = %(probeprefix)s.%(name)s ?',
93            '{',
94            probeprefix=probeprefix(),
95            name=e.name)
96
97        # Get references to userspace strings
98        for type_, name in e.args:
99            name = stap_escape(name)
100            if is_string(type_):
101                out('    try {',
102                    '        arg%(name)s_str = %(name)s ? ' +
103                    'user_string_n(%(name)s, 512) : "<null>"',
104                    '    } catch {}',
105                    name=name)
106
107        # Determine systemtap's view of variable names
108        fields = ["pid()", "gettimeofday_ns()"]
109        for type_, name in e.args:
110            name = stap_escape(name)
111            if is_string(type_):
112                fields.append("arg" + name + "_str")
113            else:
114                fields.append(name)
115
116        # Emit the entire record in a single SystemTap printf()
117        arg_str = ', '.join(arg for arg in fields)
118        fmt_str = "%d@%d " + e.name + " " + c_fmt_to_stap(e.fmt) + "\\n"
119        out('    printf("%(fmt_str)s", %(arg_str)s)',
120            fmt_str=fmt_str, arg_str=arg_str)
121
122        out('}')
123
124    out()
125