1 ##########################################################################
3 # Copyright 2010 VMware, Inc.
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 ##########################################################################/
27 """Generic retracing code generator."""
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
36 class ConstRemover(stdapi.Rebuilder):
37 '''Type visitor which strips out const qualifiers from types.'''
39 def visitConst(self, const):
42 def visitAlias(self, alias):
43 type = self.visit(alias.type)
44 if type is alias.type:
48 def visitReference(self, reference):
51 def visitOpaque(self, opaque):
55 def lookupHandle(handle, value):
56 if handle.key is None:
57 return "__%s_map[%s]" % (handle.name, value)
59 key_name, key_type = handle.key
60 return "__%s_map[%s][%s]" % (handle.name, key_name, value)
63 class ValueDeserializer(stdapi.Visitor):
65 def visitLiteral(self, literal, lvalue, rvalue):
66 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
68 def visitConst(self, const, lvalue, rvalue):
69 self.visit(const.type, lvalue, rvalue)
71 def visitAlias(self, alias, lvalue, rvalue):
72 self.visit(alias.type, lvalue, rvalue)
74 def visitEnum(self, enum, lvalue, rvalue):
75 print ' %s = (%s).toSInt();' % (lvalue, rvalue)
77 def visitBitmask(self, bitmask, lvalue, rvalue):
78 self.visit(bitmask.type, lvalue, rvalue)
80 def visitArray(self, array, lvalue, rvalue):
81 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
82 print ' if (__a%s) {' % (array.tag)
83 length = '__a%s->values.size()' % array.tag
84 print ' %s = _allocator.alloc<%s>(%s);' % (lvalue, array.type, length)
85 index = '__j' + array.tag
86 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
88 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
92 print ' %s = NULL;' % lvalue
95 def visitPointer(self, pointer, lvalue, rvalue):
96 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
97 print ' if (__a%s) {' % (pointer.tag)
98 print ' %s = _allocator.alloc<%s>();' % (lvalue, pointer.type)
100 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
103 print ' %s = NULL;' % lvalue
106 def visitIntPointer(self, pointer, lvalue, rvalue):
107 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
109 def visitLinearPointer(self, pointer, lvalue, rvalue):
110 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
112 def visitReference(self, reference, lvalue, rvalue):
113 self.visit(reference.type, lvalue, rvalue);
115 def visitHandle(self, handle, lvalue, rvalue):
116 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
117 self.visit(handle.type, lvalue, rvalue);
118 new_lvalue = lookupHandle(handle, lvalue)
119 print ' if (retrace::verbosity >= 2) {'
120 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
122 print ' %s = %s;' % (lvalue, new_lvalue)
124 def visitBlob(self, blob, lvalue, rvalue):
125 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
127 def visitString(self, string, lvalue, rvalue):
128 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
131 class OpaqueValueDeserializer(ValueDeserializer):
132 '''Value extractor that also understands opaque values.
134 Normally opaque values can't be retraced, unless they are being extracted
135 in the context of handles.'''
137 def visitOpaque(self, opaque, lvalue, rvalue):
138 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
141 class SwizzledValueRegistrator(stdapi.Visitor):
142 '''Type visitor which will register (un)swizzled value pairs, to later be
145 def visitLiteral(self, literal, lvalue, rvalue):
148 def visitAlias(self, alias, lvalue, rvalue):
149 self.visit(alias.type, lvalue, rvalue)
151 def visitEnum(self, enum, lvalue, rvalue):
154 def visitBitmask(self, bitmask, lvalue, rvalue):
157 def visitArray(self, array, lvalue, rvalue):
158 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
159 print ' if (__a%s) {' % (array.tag)
160 length = '__a%s->values.size()' % array.tag
161 index = '__j' + array.tag
162 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
164 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
169 def visitPointer(self, pointer, lvalue, rvalue):
170 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
171 print ' if (__a%s) {' % (pointer.tag)
173 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
177 def visitIntPointer(self, pointer, lvalue, rvalue):
180 def visitLinearPointer(self, pointer, lvalue, rvalue):
181 assert pointer.size is not None
182 if pointer.size is not None:
183 print r' retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
185 def visitReference(self, reference, lvalue, rvalue):
188 def visitHandle(self, handle, lvalue, rvalue):
189 print ' %s __orig_result;' % handle.type
190 OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
191 if handle.range is None:
192 rvalue = "__orig_result"
193 entry = lookupHandle(handle, rvalue)
194 print " %s = %s;" % (entry, lvalue)
195 print ' if (retrace::verbosity >= 2) {'
196 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
199 i = '__h' + handle.tag
200 lvalue = "%s + %s" % (lvalue, i)
201 rvalue = "__orig_result + %s" % (i,)
202 entry = lookupHandle(handle, rvalue)
203 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
204 print ' {entry} = {lvalue};'.format(**locals())
205 print ' if (retrace::verbosity >= 2) {'
206 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
210 def visitBlob(self, blob, lvalue, rvalue):
213 def visitString(self, string, lvalue, rvalue):
219 def retraceFunction(self, function):
220 print 'static void retrace_%s(trace::Call &call) {' % function.name
221 self.retraceFunctionBody(function)
225 def retraceInterfaceMethod(self, interface, method):
226 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, method.name)
227 self.retraceInterfaceMethodBody(interface, method)
231 def retraceFunctionBody(self, function):
232 if not function.sideeffects:
236 self.deserializeArgs(function)
238 self.invokeFunction(function)
240 self.swizzleValues(function)
242 def retraceInterfaceMethodBody(self, interface, method):
243 if not method.sideeffects:
247 self.deserializeThisPointer(interface)
249 self.deserializeArgs(method)
251 self.invokeInterfaceMethod(interface, method)
253 self.swizzleValues(method)
255 def deserializeThisPointer(self, interface):
256 print ' %s *_this;' % (interface.name,)
259 def deserializeArgs(self, function):
260 print ' retrace::ScopedAllocator _allocator;'
261 print ' (void)_allocator;'
263 for arg in function.args:
264 arg_type = ConstRemover().visit(arg.type)
265 #print ' // %s -> %s' % (arg.type, arg_type)
266 print ' %s %s;' % (arg_type, arg.name)
267 rvalue = 'call.arg(%u)' % (arg.index,)
270 self.extractArg(function, arg, arg_type, lvalue, rvalue)
271 except NotImplementedError:
273 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
277 self.failFunction(function)
278 if function.name[-1].islower():
279 sys.stderr.write('warning: unsupported %s call\n' % function.name)
282 def swizzleValues(self, function):
283 for arg in function.args:
285 arg_type = ConstRemover().visit(arg.type)
286 rvalue = 'call.arg(%u)' % (arg.index,)
289 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
290 except NotImplementedError:
291 print ' // XXX: %s' % arg.name
292 if function.type is not stdapi.Void:
296 self.regiterSwizzledValue(function.type, lvalue, rvalue)
297 except NotImplementedError:
298 print ' // XXX: result'
300 def failFunction(self, function):
301 print ' if (retrace::verbosity >= 0) {'
302 print ' retrace::unsupported(call);'
306 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
307 ValueDeserializer().visit(arg_type, lvalue, rvalue)
309 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
310 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
312 def regiterSwizzledValue(self, type, lvalue, rvalue):
313 visitor = SwizzledValueRegistrator()
314 visitor.visit(type, lvalue, rvalue)
316 def invokeFunction(self, function):
317 arg_names = ", ".join(function.argNames())
318 if function.type is not stdapi.Void:
319 print ' %s __result;' % (function.type)
320 print ' __result = %s(%s);' % (function.name, arg_names)
321 print ' (void)__result;'
323 print ' %s(%s);' % (function.name, arg_names)
325 def invokeInterfaceMethod(self, interface, method):
326 arg_names = ", ".join(method.argNames())
327 if method.type is not stdapi.Void:
328 print ' %s __result;' % (method.type)
329 print ' __result = _this->%s(%s);' % (method.name, arg_names)
330 print ' (void)__result;'
332 print ' _this->%s(%s);' % (method.name, arg_names)
334 def filterFunction(self, function):
337 table_name = 'retrace::callbacks'
339 def retraceApi(self, api):
341 print '#include "os_time.hpp"'
342 print '#include "trace_parser.hpp"'
343 print '#include "retrace.hpp"'
346 types = api.getAllTypes()
347 handles = [type for type in types if isinstance(type, stdapi.Handle)]
349 for handle in handles:
350 if handle.name not in handle_names:
351 if handle.key is None:
352 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
354 key_name, key_type = handle.key
355 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
356 handle_names.add(handle.name)
359 functions = filter(self.filterFunction, api.functions)
360 for function in functions:
361 self.retraceFunction(function)
362 interfaces = api.getAllInterfaces()
363 for interface in interfaces:
364 for method in interface.iterMethods():
365 self.retraceInterfaceMethod(interface, method)
367 print 'const retrace::Entry %s[] = {' % self.table_name
368 for function in functions:
369 print ' {"%s", &retrace_%s},' % (function.name, function.name)
370 for interface in interfaces:
371 for method in interface.iterMethods():
372 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
373 print ' {NULL, NULL}'