1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4""" 5Generate .stp file that printfs log messages (DTrace with SystemTAP only). 6""" 7 8__author__ = "Daniel P. Berrange <berrange@redhat.com>" 9__copyright__ = "Copyright (C) 2014-2019, Red Hat, Inc." 10__license__ = "GPL version 2 or (at your option) any later version" 11 12__maintainer__ = "Daniel Berrange" 13__email__ = "berrange@redhat.com" 14 15import re 16 17from tracetool import out 18from tracetool.backend.dtrace import binary, probeprefix 19from tracetool.backend.simple import is_string 20from tracetool.format.stap import stap_escape 21 22def global_var_name(name): 23 return probeprefix().replace(".", "_") + "_" + name 24 25STATE_SKIP = 0 26STATE_LITERAL = 1 27STATE_MACRO = 2 28 29def c_macro_to_format(macro): 30 if macro.startswith("PRI"): 31 return macro[3] 32 33 raise Exception("Unhandled macro '%s'" % macro) 34 35def c_fmt_to_stap(fmt): 36 state = 0 37 bits = [] 38 literal = "" 39 macro = "" 40 escape = 0; 41 for i in range(len(fmt)): 42 if fmt[i] == '\\': 43 if escape: 44 escape = 0 45 else: 46 escape = 1 47 if state != STATE_LITERAL: 48 raise Exception("Unexpected escape outside string literal") 49 literal = literal + fmt[i] 50 elif fmt[i] == '"' and not escape: 51 if state == STATE_LITERAL: 52 state = STATE_SKIP 53 bits.append(literal) 54 literal = "" 55 else: 56 if state == STATE_MACRO: 57 bits.append(c_macro_to_format(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 fmt = re.sub("%(\d*)z(x|u|d)", "%\\1\\2", "".join(bits)) 82 return fmt 83 84def generate(events, backend, group): 85 out('/* This file is autogenerated by tracetool, do not edit. */', 86 '') 87 88 for event_id, e in enumerate(events): 89 if 'disable' in e.properties: 90 continue 91 92 out('probe %(probeprefix)s.log.%(name)s = %(probeprefix)s.%(name)s ?', 93 '{', 94 probeprefix=probeprefix(), 95 name=e.name) 96 97 # Get references to userspace strings 98 for type_, name in e.args: 99 name = stap_escape(name) 100 if is_string(type_): 101 out(' try {', 102 ' arg%(name)s_str = %(name)s ? ' + 103 'user_string_n(%(name)s, 512) : "<null>"', 104 ' } catch {}', 105 name=name) 106 107 # Determine systemtap's view of variable names 108 fields = ["pid()", "gettimeofday_ns()"] 109 for type_, name in e.args: 110 name = stap_escape(name) 111 if is_string(type_): 112 fields.append("arg" + name + "_str") 113 else: 114 fields.append(name) 115 116 # Emit the entire record in a single SystemTap printf() 117 arg_str = ', '.join(arg for arg in fields) 118 fmt_str = "%d@%d " + e.name + " " + c_fmt_to_stap(e.fmt) + "\\n" 119 out(' printf("%(fmt_str)s", %(arg_str)s)', 120 fmt_str=fmt_str, arg_str=arg_str) 121 122 out('}') 123 124 out() 125