]>
Commit | Line | Data |
---|---|---|
c1008fd0 | 1 | #!/usr/bin/python |
bc65bf81 | 2 | # vim: et sta sts=4 sw=4 ts=8 |
c1008fd0 SC |
3 | |
4 | # This handles the systemtap equivalent of | |
d294a649 | 5 | # $(DTRACE) $(DTRACEFLAGS) -G -s $^ -o $@ |
c1008fd0 | 6 | # $(DTRACE) $(DTRACEFLAGS) -h -s $^ -o $@ |
d294a649 SC |
7 | # which is a step that builds DTrace provider and probe definitions |
8 | ||
b1568fd8 | 9 | # Copyright (C) 2009, 2010, 2011 Red Hat Inc. |
c1008fd0 SC |
10 | # |
11 | # This file is part of systemtap, and is free software. You can | |
12 | # redistribute it and/or modify it under the terms of the GNU General | |
13 | # Public License (GPL); either version 2, or (at your option) any | |
14 | # later version. | |
15 | ||
398d1973 SC |
16 | import os |
17 | import posix | |
398d1973 | 18 | import sys |
4c353c3a | 19 | import shlex |
c0d0d868 | 20 | from subprocess import call |
e3c5bcd9 | 21 | from tempfile import mkstemp |
c1008fd0 | 22 | |
d4168b3a JS |
23 | def init_gettext(): |
24 | if "@USE_NLS@" == "yes": | |
25 | import gettext | |
26 | # hack around autoconf's weird stepwise substitution | |
27 | datarootdir = "@datarootdir@".replace("${prefix}", "@STAP_PREFIX@") | |
28 | localedir = "@LOCALEDIR@".replace("${datarootdir}", datarootdir) | |
29 | gettext.bindtextdomain('@PACKAGE@', localedir) | |
30 | gettext.textdomain('@PACKAGE@') | |
31 | return gettext.gettext | |
32 | return str | |
398d1973 | 33 | |
50e767ff JS |
34 | class _provider(object): |
35 | def __init__(self): | |
36 | self.semaphores_def = "\n" | |
37 | ||
4f46087f | 38 | # is the type a basic scalar type? |
398d1973 SC |
39 | def __basic_type(self, arg): |
40 | basic_types = [ "int","int*","long","long*","short","short int", | |
41 | "unsigned long","char","char*","float","double" ] | |
4f46087f SC |
42 | split_arg = arg.rsplit(None,1) |
43 | return (split_arg[0].strip() in basic_types) & (arg.find("[") == -1) | |
50e767ff | 44 | |
a49946ac | 45 | def __typedef_append(self, typedefs, this_probe, arg, c, add_typedefs): |
5111fc3e SC |
46 | if (add_typedefs): |
47 | split_arg = arg.rsplit(None,1) | |
398d1973 | 48 | if (self.__basic_type(arg)): |
4f46087f | 49 | return typedefs |
5111fc3e SC |
50 | type_name = " %s_arg%d" % (this_probe.replace("__","_"),c) |
51 | if (len(split_arg) > 1): | |
52 | typedefs += ("typedef " + arg.replace(" " + split_arg[1].split("[")[0].lstrip("*"),type_name).strip() + "; ") | |
53 | typedefs += (type_name + type_name + "_v;\n") | |
54 | else: | |
55 | typedefs += ("typedef " + arg.strip() + type_name + "; ") | |
56 | typedefs += (type_name + type_name + "_v;\n") | |
57 | return typedefs | |
50e767ff | 58 | |
398d1973 | 59 | def __semaphore_def_append(self, this_probe): |
8faa1fc5 | 60 | # NB: unsigned short is fixed in ABI |
ebbd2b45 | 61 | self.semaphores_def += '#if defined STAP_SDT_V1\n' |
398d1973 SC |
62 | self.semaphores_def += '#define %s_%s_semaphore %s_semaphore\n' % \ |
63 | (self.provider,this_probe,this_probe) | |
a794dbeb | 64 | self.semaphores_def += '#endif\n' |
5561d47d SC |
65 | self.semaphores_def += '#if defined STAP_SDT_V1 || defined STAP_SDT_V2 \n' |
66 | self.semaphores_def += "__extension__ unsigned short %s_%s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % \ | |
67 | (self.provider,this_probe) | |
68 | self.semaphores_def += '#else\n' | |
8f549224 | 69 | self.semaphores_def += "__extension__ unsigned short %s_%s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\"))) __attribute__ ((visibility (\"hidden\")));\n" % \ |
398d1973 | 70 | (self.provider,this_probe) |
5561d47d | 71 | self.semaphores_def += '#endif\n' |
50e767ff | 72 | |
4f46087f SC |
73 | def semaphore_def_write(self, file): |
74 | file.write(self.semaphores_def) | |
50e767ff | 75 | |
5111fc3e | 76 | def generate(self, provider, header, add_typedefs): |
c1008fd0 SC |
77 | have_provider = False |
78 | self.f = open(provider) | |
79 | self.h = open(header,mode='w') | |
2a22df62 | 80 | self.h.write("/* Generated by the Systemtap dtrace wrapper */\n") |
6b51ee12 SC |
81 | self.h.write("\n#define _SDT_HAS_SEMAPHORES 1\n\n") |
82 | self.h.write("\n#define STAP_HAS_SEMAPHORES 1 /* deprecated */\n\n") | |
c1008fd0 SC |
83 | self.h.write("\n#include <sys/sdt.h>\n\n") |
84 | in_comment = False | |
5111fc3e | 85 | typedefs = "" |
c1008fd0 SC |
86 | while (True): |
87 | line = self.f.readline() | |
88 | if (line == ""): | |
89 | break | |
5111fc3e | 90 | if (line.find("/*") != -1): |
c1008fd0 | 91 | in_comment = True |
5111fc3e | 92 | if (line.find("*/") != -1): |
c1008fd0 SC |
93 | in_comment = False |
94 | continue | |
95 | if (in_comment): | |
96 | continue | |
5111fc3e | 97 | if (line.find("provider") != -1): |
c1008fd0 SC |
98 | tokens = line.split() |
99 | have_provider = True | |
100 | self.provider = tokens[1] | |
5111fc3e SC |
101 | elif (not have_provider): |
102 | if (add_typedefs): | |
103 | self.h.write (line) | |
104 | elif (have_provider and line.find("probe ") != -1): | |
c1008fd0 SC |
105 | while (line.find(")") < 0): |
106 | line += self.f.readline() | |
107 | this_probe = line[line.find("probe ")+5:line.find("(")].strip() | |
108 | this_probe_canon = self.provider.upper() + "_" + this_probe.replace("__","_").upper() | |
109 | args = (line[line.find("(")+1:line.find(")")]) | |
5111fc3e SC |
110 | args_string = "" |
111 | arg = "" | |
c1008fd0 SC |
112 | i = 0 |
113 | c = 0 | |
398d1973 | 114 | self.__semaphore_def_append (this_probe) |
c1008fd0 SC |
115 | while (i < len(args)): |
116 | if (args[i:i+1] == ","): | |
398d1973 SC |
117 | args_string = ('%s %s,' % |
118 | (args_string, arg.strip())) | |
c1008fd0 | 119 | c += 1 |
a49946ac JS |
120 | typedefs = self.__typedef_append (typedefs, this_probe, |
121 | arg, c, add_typedefs) | |
5111fc3e | 122 | arg = "" |
c1008fd0 | 123 | else: |
5111fc3e | 124 | arg = arg + args[i] |
c1008fd0 | 125 | i += 1 |
5111fc3e SC |
126 | if (i != 0): |
127 | args_string = ('%s %s' % (args_string, arg.strip())) | |
398d1973 | 128 | if (not args_string): |
46607641 | 129 | c = 0 |
63877c9a | 130 | stap_str = "DTRACE_PROBE(%s,%s" % \ |
398d1973 | 131 | (self.provider,this_probe) |
46607641 SC |
132 | else: |
133 | c += 1 | |
a49946ac JS |
134 | typedefs = self.__typedef_append (typedefs, this_probe, |
135 | arg, c, add_typedefs) | |
63877c9a | 136 | stap_str = "DTRACE_PROBE%d(%s,%s" % \ |
398d1973 | 137 | (c,self.provider,this_probe) |
4f988cd3 | 138 | define_str = "#define %s(" % (this_probe_canon) |
46607641 | 139 | i = 1 |
4f988cd3 | 140 | while (i <= c): |
2a22df62 | 141 | if (i != 1): |
4f988cd3 | 142 | define_str += "," |
46607641 SC |
143 | define_str = define_str + "arg%s" % (i); |
144 | stap_str = stap_str + ",arg%s" % (i); | |
4f988cd3 | 145 | i += 1 |
398d1973 SC |
146 | self.h.write('/* %s (%s) */\n' % \ |
147 | (this_probe_canon,args_string)) | |
148 | self.h.write('#if defined STAP_SDT_V1\n') | |
149 | self.h.write('#define %s_ENABLED() __builtin_expect (%s_semaphore, 0)\n' % \ | |
150 | (this_probe_canon,this_probe)) | |
151 | self.h.write('#define %s_%s_semaphore %s_semaphore\n' % \ | |
152 | (self.provider,this_probe,this_probe)) | |
153 | self.h.write('#else\n') | |
154 | self.h.write('#define %s_ENABLED() __builtin_expect (%s_%s_semaphore, 0)\n' % \ | |
155 | (this_probe_canon,self.provider,this_probe)) | |
156 | self.h.write('#endif\n') | |
8faa1fc5 | 157 | # NB: unsigned short is fixed in ABI |
398d1973 SC |
158 | self.h.write("__extension__ extern unsigned short %s_%s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % \ |
159 | (self.provider,this_probe)) | |
160 | self.h.write(define_str + ") \\\n") | |
161 | self.h.write(stap_str + ")\n\n") | |
5111fc3e SC |
162 | elif (line.find("}") != -1 and have_provider): |
163 | have_provider = False | |
164 | if (add_typedefs): | |
398d1973 | 165 | self.h.write(typedefs) |
5111fc3e SC |
166 | self.h.close() |
167 | ||
c1008fd0 | 168 | |
c1008fd0 | 169 | def usage (): |
bad3553d | 170 | print _("Usage ") + sys.argv[0] + " [--help] [-h | -G] [-C [-I<Path>]] -s File.d [-o <File>]" |
5111fc3e SC |
171 | |
172 | def help (): | |
173 | usage() | |
bad3553d LB |
174 | print _("Where -h builds a systemtap header file from the .d file") |
175 | print _(" -C when used with -h, also run cpp preprocessor") | |
176 | print _(" -o specifies an explicit output file name,") | |
177 | print _(" the default for -G is file.o and -h is file.h") | |
178 | print _(" -I when running cpp pass through this -I include Path") | |
179 | print _(" -s specifies the name of the .d input file") | |
180 | print _(" -G builds a stub file.o from file.d,") | |
181 | print _(" which is required by some packages that use dtrace.") | |
c1008fd0 SC |
182 | sys.exit(1) |
183 | ||
4f988cd3 SC |
184 | |
185 | ######################################################################## | |
186 | # main | |
187 | ######################################################################## | |
188 | ||
a49946ac JS |
189 | def main(): |
190 | if (len(sys.argv) < 2): | |
191 | usage() | |
12aad6f0 | 192 | return 1 |
c1008fd0 | 193 | |
a49946ac JS |
194 | i = 1 |
195 | build_header = False | |
196 | build_source = False | |
197 | add_typedefs = False | |
198 | keep_temps = False | |
199 | use_cpp = False | |
b571f934 | 200 | suffix = "" |
a49946ac JS |
201 | filename = "" |
202 | s_filename = "" | |
203 | includes = [] | |
204 | defines = [] | |
205 | while (i < len(sys.argv)): | |
206 | if (sys.argv[i] == "-o"): | |
207 | i += 1 | |
208 | filename = sys.argv[i] | |
209 | elif (sys.argv[i] == "-s"): | |
210 | i += 1 | |
211 | s_filename = sys.argv[i] | |
212 | elif (sys.argv[i] == "-C"): | |
213 | use_cpp = True | |
214 | elif (sys.argv[i].startswith("-D")): | |
215 | defines.append(sys.argv[i]) | |
216 | elif (sys.argv[i] == "-h"): | |
217 | build_header = True | |
b571f934 | 218 | suffix = ".h" |
a49946ac JS |
219 | elif (sys.argv[i].startswith("-I")): |
220 | includes.append(sys.argv[i]) | |
221 | elif (sys.argv[i] == "-G"): | |
222 | build_source = True | |
b571f934 | 223 | suffix = ".o" |
a49946ac JS |
224 | elif (sys.argv[i] == "-k"): |
225 | keep_temps = True | |
226 | elif (sys.argv[i] == "--types"): | |
227 | add_typedefs = True | |
228 | elif (sys.argv[i] == "--help"): | |
229 | help() | |
c1008fd0 | 230 | i += 1 |
a49946ac | 231 | if (build_header == False and build_source == False): |
dd66ed3f | 232 | usage() |
12aad6f0 | 233 | return 1 |
a49946ac JS |
234 | |
235 | if (s_filename != "" and use_cpp): | |
236 | (d,fn) = mkstemp(suffix=".d") | |
237 | CPP = os.environ.get("CPP", "cpp") | |
4c353c3a | 238 | retcode = call(shlex.split(CPP) + includes + defines + [s_filename, fn]) |
a49946ac JS |
239 | if (retcode != 0): |
240 | print "\"cpp includes s_filename\" failed" | |
241 | usage() | |
12aad6f0 | 242 | return 1 |
a49946ac JS |
243 | s_filename = fn |
244 | if (filename == ""): | |
245 | if (s_filename != ""): | |
246 | (filename,ext) = os.path.splitext(s_filename) | |
247 | filename = os.path.basename(filename) | |
248 | else: | |
249 | usage() | |
12aad6f0 | 250 | return 1 |
c1008fd0 | 251 | else: |
b571f934 | 252 | suffix = "" |
8bab68f6 | 253 | if (build_header): |
a49946ac | 254 | providers = _provider() |
b571f934 | 255 | providers.generate(s_filename, filename + suffix, add_typedefs) |
a49946ac JS |
256 | elif (build_source): |
257 | (basename,ext) = os.path.splitext(s_filename) | |
4f46087f | 258 | |
a49946ac JS |
259 | # create for semaphore_def_write |
260 | providers = _provider() | |
261 | (d,fn) = mkstemp(suffix=".h") | |
262 | providers.generate(s_filename, fn, add_typedefs) | |
263 | if (not keep_temps): | |
264 | os.remove(fn) | |
265 | else: | |
266 | print "header: " + fn | |
4f46087f | 267 | |
a49946ac JS |
268 | (d,fn) = mkstemp(suffix=".c") |
269 | f = open(fn,mode='w') | |
270 | f.write("static __dtrace () {}\n") | |
271 | f.write("\n#include <sys/sdt.h>\n\n") | |
272 | providers.semaphore_def_write(f) | |
273 | f.close() | |
274 | CC = os.environ.get("CC", "gcc") | |
275 | CFLAGS = "-g " + os.environ.get("CFLAGS", "") | |
4c353c3a | 276 | retcode = call(shlex.split(CC) + defines + includes + shlex.split(CFLAGS) + |
f6b267eb | 277 | ["-fPIC", "-I.", "-I@prefix@/include", "-c", fn, "-o", |
b571f934 SC |
278 | filename + suffix], shell=False) |
279 | if (retcode != 0): | |
280 | print "\"gcc " + fn + "\" failed" | |
281 | usage() | |
12aad6f0 | 282 | return 1 |
bc65bf81 | 283 | if (not keep_temps): |
a49946ac | 284 | os.remove(fn) |
bc65bf81 | 285 | else: |
a49946ac JS |
286 | print "source: " + fn |
287 | if (use_cpp): | |
288 | if (not keep_temps): | |
289 | os.remove(s_filename) | |
290 | else: | |
291 | print "cpp: " + s_filename | |
12aad6f0 | 292 | return 0 |
a49946ac JS |
293 | |
294 | if __name__ == "__main__": | |
d4168b3a | 295 | _ = init_gettext() |
12aad6f0 | 296 | sys.exit(main()) |