# -*- coding: utf-8 -*- """ Generate .stp file that printfs log messages (DTrace with SystemTAP only). """ __author__ = "Daniel P. Berrange " __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) : ""', ' } 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()