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