diff options
Diffstat (limited to 'scripts/tracetool/format/log_stap.py')
-rw-r--r-- | scripts/tracetool/format/log_stap.py | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/scripts/tracetool/format/log_stap.py b/scripts/tracetool/format/log_stap.py new file mode 100644 index 0000000000..3ccbc09d61 --- /dev/null +++ b/scripts/tracetool/format/log_stap.py @@ -0,0 +1,127 @@ +#!/usr/bin/env 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] + + if macro == "TARGET_FMT_plx": + return "%016x" + + 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)) + 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) + + fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".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() |