Merge remote-tracking branch 'remotes/elmarco/tags/slirp-pull-request' into staging
[qemu.git] / scripts / tracetool / format / log_stap.py
1 # -*- coding: utf-8 -*-
2
3 """
4 Generate .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
14 import re
15
16 from tracetool import out
17 from tracetool.backend.dtrace import binary, probeprefix
18 from tracetool.backend.simple import is_string
19 from tracetool.format.stap import stap_escape
20
21 def global_var_name(name):
22 return probeprefix().replace(".", "_") + "_" + name
23
24 STATE_SKIP = 0
25 STATE_LITERAL = 1
26 STATE_MACRO = 2
27
28 def c_macro_to_format(macro):
29 if macro.startswith("PRI"):
30 return macro[3]
31
32 raise Exception("Unhandled macro '%s'" % macro)
33
34 def 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 state = STATE_LITERAL
58 elif fmt[i] == ' ' or fmt[i] == '\t':
59 if state == STATE_MACRO:
60 bits.append(c_macro_to_format(macro))
61 macro = ""
62 state = STATE_SKIP
63 elif state == STATE_LITERAL:
64 literal = literal + fmt[i]
65 else:
66 escape = 0
67 if state == STATE_SKIP:
68 state = STATE_MACRO
69
70 if state == STATE_LITERAL:
71 literal = literal + fmt[i]
72 else:
73 macro = macro + fmt[i]
74
75 if state == STATE_MACRO:
76 bits.append(c_macro_to_format(macro))
77 elif state == STATE_LITERAL:
78 bits.append(literal)
79
80 fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".join(bits))
81 return fmt
82
83 def generate(events, backend, group):
84 out('/* This file is autogenerated by tracetool, do not edit. */',
85 '')
86
87 for event_id, e in enumerate(events):
88 if 'disable' in e.properties:
89 continue
90
91 out('probe %(probeprefix)s.log.%(name)s = %(probeprefix)s.%(name)s ?',
92 '{',
93 probeprefix=probeprefix(),
94 name=e.name)
95
96 # Get references to userspace strings
97 for type_, name in e.args:
98 name = stap_escape(name)
99 if is_string(type_):
100 out(' try {',
101 ' arg%(name)s_str = %(name)s ? ' +
102 'user_string_n(%(name)s, 512) : "<null>"',
103 ' } catch {}',
104 name=name)
105
106 # Determine systemtap's view of variable names
107 fields = ["pid()", "gettimeofday_ns()"]
108 for type_, name in e.args:
109 name = stap_escape(name)
110 if is_string(type_):
111 fields.append("arg" + name + "_str")
112 else:
113 fields.append(name)
114
115 # Emit the entire record in a single SystemTap printf()
116 arg_str = ', '.join(arg for arg in fields)
117 fmt_str = "%d@%d " + e.name + " " + c_fmt_to_stap(e.fmt) + "\\n"
118 out(' printf("%(fmt_str)s", %(arg_str)s)',
119 fmt_str=fmt_str, arg_str=arg_str)
120
121 out('}')
122
123 out()