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 state = STATE_LITERAL 58 elif fmt[i] == ' ' or fmt[i] == '\t': 59 if state == STATE_MACRO: 60 bits.append(c_macro_to_format(macro)) 61 macro = "" 62 state = STATE_SKIP 63 elif state == STATE_LITERAL: 64 literal = literal + fmt[i] 65 else: 66 escape = 0 67 if state == STATE_SKIP: 68 state = STATE_MACRO 69 70 if state == STATE_LITERAL: 71 literal = literal + fmt[i] 72 else: 73 macro = macro + fmt[i] 74 75 if state == STATE_MACRO: 76 bits.append(c_macro_to_format(macro)) 77 elif state == STATE_LITERAL: 78 bits.append(literal) 79 80 fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".join(bits)) 81 return fmt 82 83def generate(events, backend, group): 84 out('/* This file is autogenerated by tracetool, do not edit. */', 85 '') 86 87 for event_id, e in enumerate(events): 88 if 'disable' in e.properties: 89 continue 90 91 out('probe %(probeprefix)s.log.%(name)s = %(probeprefix)s.%(name)s ?', 92 '{', 93 probeprefix=probeprefix(), 94 name=e.name) 95 96 # Get references to userspace strings 97 for type_, name in e.args: 98 name = stap_escape(name) 99 if is_string(type_): 100 out(' try {', 101 ' arg%(name)s_str = %(name)s ? ' + 102 'user_string_n(%(name)s, 512) : "<null>"', 103 ' } catch {}', 104 name=name) 105 106 # Determine systemtap's view of variable names 107 fields = ["pid()", "gettimeofday_ns()"] 108 for type_, name in e.args: 109 name = stap_escape(name) 110 if is_string(type_): 111 fields.append("arg" + name + "_str") 112 else: 113 fields.append(name) 114 115 # Emit the entire record in a single SystemTap printf() 116 arg_str = ', '.join(arg for arg in fields) 117 fmt_str = "%d@%d " + e.name + " " + c_fmt_to_stap(e.fmt) + "\\n" 118 out(' printf("%(fmt_str)s", %(arg_str)s)', 119 fmt_str=fmt_str, arg_str=arg_str) 120 121 out('}') 122 123 out() 124