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