forked from mirror/qemu
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.9 KiB
Python
130 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Generate .stp file that printfs log messages (DTrace with SystemTAP only).
|
|
"""
|
|
|
|
__author__ = "Daniel P. Berrange <berrange@redhat.com>"
|
|
__copyright__ = "Copyright (C) 2014-2019, Red Hat, Inc."
|
|
__license__ = "GPL version 2 or (at your option) any later version"
|
|
|
|
__maintainer__ = "Daniel Berrange"
|
|
__email__ = "berrange@redhat.com"
|
|
|
|
import re
|
|
|
|
from tracetool import out
|
|
from tracetool.backend.dtrace import binary, probeprefix
|
|
from tracetool.backend.simple import is_string
|
|
from tracetool.format.stap import stap_escape
|
|
|
|
def global_var_name(name):
|
|
return probeprefix().replace(".", "_") + "_" + name
|
|
|
|
STATE_SKIP = 0
|
|
STATE_LITERAL = 1
|
|
STATE_MACRO = 2
|
|
|
|
def c_macro_to_format(macro):
|
|
if macro.startswith("PRI"):
|
|
return macro[3]
|
|
|
|
raise Exception("Unhandled macro '%s'" % macro)
|
|
|
|
def c_fmt_to_stap(fmt):
|
|
state = 0
|
|
bits = []
|
|
literal = ""
|
|
macro = ""
|
|
escape = 0;
|
|
for i in range(len(fmt)):
|
|
if fmt[i] == '\\':
|
|
if escape:
|
|
escape = 0
|
|
else:
|
|
escape = 1
|
|
if state != STATE_LITERAL:
|
|
raise Exception("Unexpected escape outside string literal")
|
|
literal = literal + fmt[i]
|
|
elif fmt[i] == '"' and not escape:
|
|
if state == STATE_LITERAL:
|
|
state = STATE_SKIP
|
|
bits.append(literal)
|
|
literal = ""
|
|
else:
|
|
if state == STATE_MACRO:
|
|
bits.append(c_macro_to_format(macro))
|
|
macro = ""
|
|
state = STATE_LITERAL
|
|
elif fmt[i] == ' ' or fmt[i] == '\t':
|
|
if state == STATE_MACRO:
|
|
bits.append(c_macro_to_format(macro))
|
|
macro = ""
|
|
state = STATE_SKIP
|
|
elif state == STATE_LITERAL:
|
|
literal = literal + fmt[i]
|
|
else:
|
|
escape = 0
|
|
if state == STATE_SKIP:
|
|
state = STATE_MACRO
|
|
|
|
if state == STATE_LITERAL:
|
|
literal = literal + fmt[i]
|
|
else:
|
|
macro = macro + fmt[i]
|
|
|
|
if state == STATE_MACRO:
|
|
bits.append(c_macro_to_format(macro))
|
|
elif state == STATE_LITERAL:
|
|
bits.append(literal)
|
|
|
|
# All variables in systemtap are 64-bit in size
|
|
# The "%l" integer size qualifier is thus redundant
|
|
# and "%ll" is not valid at all. Similarly the size_t
|
|
# based "%z" size qualifier is not valid. We just
|
|
# strip all size qualifiers for sanity.
|
|
fmt = re.sub("%(\d*)(l+|z)(x|u|d)", "%\\1\\3", "".join(bits))
|
|
return fmt
|
|
|
|
def generate(events, backend, group):
|
|
out('/* This file is autogenerated by tracetool, do not edit. */',
|
|
'')
|
|
|
|
for event_id, e in enumerate(events):
|
|
if 'disable' in e.properties:
|
|
continue
|
|
|
|
out('probe %(probeprefix)s.log.%(name)s = %(probeprefix)s.%(name)s ?',
|
|
'{',
|
|
probeprefix=probeprefix(),
|
|
name=e.name)
|
|
|
|
# Get references to userspace strings
|
|
for type_, name in e.args:
|
|
name = stap_escape(name)
|
|
if is_string(type_):
|
|
out(' try {',
|
|
' arg%(name)s_str = %(name)s ? ' +
|
|
'user_string_n(%(name)s, 512) : "<null>"',
|
|
' } catch {}',
|
|
name=name)
|
|
|
|
# Determine systemtap's view of variable names
|
|
fields = ["pid()", "gettimeofday_ns()"]
|
|
for type_, name in e.args:
|
|
name = stap_escape(name)
|
|
if is_string(type_):
|
|
fields.append("arg" + name + "_str")
|
|
else:
|
|
fields.append(name)
|
|
|
|
# Emit the entire record in a single SystemTap printf()
|
|
arg_str = ', '.join(arg for arg in fields)
|
|
fmt_str = "%d@%d " + e.name + " " + c_fmt_to_stap(e.fmt) + "\\n"
|
|
out(' printf("%(fmt_str)s", %(arg_str)s)',
|
|
fmt_str=fmt_str, arg_str=arg_str)
|
|
|
|
out('}')
|
|
|
|
out()
|