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