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 MutableRebuilder(stdapi.Rebuilder):
37 '''Type visitor which derives a mutable type.'''
39 def visitConst(self, const):
40 # Strip out const qualifier
43 def visitAlias(self, alias):
44 # Tear the alias on type changes
45 type = self.visit(alias.type)
46 if type is alias.type:
50 def visitReference(self, reference):
51 # Strip out references
54 def visitOpaque(self, opaque):
59 def lookupHandle(handle, value):
60 if handle.key is None:
61 return "__%s_map[%s]" % (handle.name, value)
63 key_name, key_type = handle.key
64 return "__%s_map[%s][%s]" % (handle.name, key_name, value)
67 class ValueAllocator(stdapi.Visitor):
69 def visitLiteral(self, literal, lvalue, rvalue):
72 def visitConst(self, const, lvalue, rvalue):
73 self.visit(const.type, lvalue, rvalue)
75 def visitAlias(self, alias, lvalue, rvalue):
76 self.visit(alias.type, lvalue, rvalue)
78 def visitEnum(self, enum, lvalue, rvalue):
81 def visitBitmask(self, bitmask, lvalue, rvalue):
84 def visitArray(self, array, lvalue, rvalue):
85 print ' %s = _allocator.alloc<%s>(&%s);' % (lvalue, array.type, rvalue)
87 def visitPointer(self, pointer, lvalue, rvalue):
88 print ' %s = _allocator.alloc<%s>(&%s);' % (lvalue, pointer.type, rvalue)
90 def visitIntPointer(self, pointer, lvalue, rvalue):
93 def visitObjPointer(self, pointer, lvalue, rvalue):
96 def visitLinearPointer(self, pointer, lvalue, rvalue):
99 def visitReference(self, reference, lvalue, rvalue):
100 self.visit(reference.type, lvalue, rvalue);
102 def visitHandle(self, handle, lvalue, rvalue):
105 def visitBlob(self, blob, lvalue, rvalue):
108 def visitString(self, string, lvalue, rvalue):
111 def visitStruct(self, struct, lvalue, rvalue):
114 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
115 self.visit(polymorphic.defaultType, lvalue, rvalue)
118 class ValueDeserializer(stdapi.Visitor):
120 def visitLiteral(self, literal, lvalue, rvalue):
121 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
123 def visitConst(self, const, lvalue, rvalue):
124 self.visit(const.type, lvalue, rvalue)
126 def visitAlias(self, alias, lvalue, rvalue):
127 self.visit(alias.type, lvalue, rvalue)
129 def visitEnum(self, enum, lvalue, rvalue):
130 print ' %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
132 def visitBitmask(self, bitmask, lvalue, rvalue):
133 self.visit(bitmask.type, lvalue, rvalue)
135 def visitArray(self, array, lvalue, rvalue):
137 tmp = '__a_' + array.tag + '_' + str(self.seq)
140 print ' if (%s) {' % (lvalue,)
141 print ' const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
142 length = '%s->values.size()' % (tmp,)
143 index = '__j' + array.tag
144 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
146 self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
151 def visitPointer(self, pointer, lvalue, rvalue):
152 tmp = '__a_' + pointer.tag + '_' + str(self.seq)
155 print ' if (%s) {' % (lvalue,)
156 print ' const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
158 self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
162 def visitIntPointer(self, pointer, lvalue, rvalue):
163 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
165 def visitObjPointer(self, pointer, lvalue, rvalue):
166 old_lvalue = '(%s).toUIntPtr()' % (rvalue,)
167 new_lvalue = '_obj_map[%s]' % (old_lvalue,)
168 print ' if (retrace::verbosity >= 2) {'
169 print ' std::cout << std::hex << "obj 0x" << size_t(%s) << " <- 0x" << size_t(%s) << std::dec <<"\\n";' % (old_lvalue, new_lvalue)
171 print ' %s = static_cast<%s>(%s);' % (lvalue, pointer, new_lvalue)
173 def visitLinearPointer(self, pointer, lvalue, rvalue):
174 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
176 def visitReference(self, reference, lvalue, rvalue):
177 self.visit(reference.type, lvalue, rvalue);
179 def visitHandle(self, handle, lvalue, rvalue):
180 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
181 self.visit(handle.type, lvalue, rvalue);
182 new_lvalue = lookupHandle(handle, lvalue)
183 print ' if (retrace::verbosity >= 2) {'
184 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
186 print ' %s = %s;' % (lvalue, new_lvalue)
188 def visitBlob(self, blob, lvalue, rvalue):
189 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
191 def visitString(self, string, lvalue, rvalue):
192 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
196 def visitStruct(self, struct, lvalue, rvalue):
197 tmp = '__s_' + struct.tag + '_' + str(self.seq)
200 print ' const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
201 print ' assert(%s);' % (tmp)
202 for i in range(len(struct.members)):
203 member_type, member_name = struct.members[i]
204 self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
206 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
207 self.visit(polymorphic.defaultType, lvalue, rvalue)
210 class OpaqueValueDeserializer(ValueDeserializer):
211 '''Value extractor that also understands opaque values.
213 Normally opaque values can't be retraced, unless they are being extracted
214 in the context of handles.'''
216 def visitOpaque(self, opaque, lvalue, rvalue):
217 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
220 class SwizzledValueRegistrator(stdapi.Visitor):
221 '''Type visitor which will register (un)swizzled value pairs, to later be
224 def visitLiteral(self, literal, lvalue, rvalue):
227 def visitAlias(self, alias, lvalue, rvalue):
228 self.visit(alias.type, lvalue, rvalue)
230 def visitEnum(self, enum, lvalue, rvalue):
233 def visitBitmask(self, bitmask, lvalue, rvalue):
236 def visitArray(self, array, lvalue, rvalue):
237 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
238 print ' if (__a%s) {' % (array.tag)
239 length = '__a%s->values.size()' % array.tag
240 index = '__j' + array.tag
241 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
243 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
248 def visitPointer(self, pointer, lvalue, rvalue):
249 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
250 print ' if (__a%s) {' % (pointer.tag)
252 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
256 def visitIntPointer(self, pointer, lvalue, rvalue):
259 def visitObjPointer(self, pointer, lvalue, rvalue):
260 print r' _obj_map[(%s).toUIntPtr()] = %s;' % (rvalue, lvalue)
262 def visitLinearPointer(self, pointer, lvalue, rvalue):
263 assert pointer.size is not None
264 if pointer.size is not None:
265 print r' retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
267 def visitReference(self, reference, lvalue, rvalue):
270 def visitHandle(self, handle, lvalue, rvalue):
271 print ' %s __orig_result;' % handle.type
272 OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
273 if handle.range is None:
274 rvalue = "__orig_result"
275 entry = lookupHandle(handle, rvalue)
276 print " %s = %s;" % (entry, lvalue)
277 print ' if (retrace::verbosity >= 2) {'
278 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
281 i = '__h' + handle.tag
282 lvalue = "%s + %s" % (lvalue, i)
283 rvalue = "__orig_result + %s" % (i,)
284 entry = lookupHandle(handle, rvalue)
285 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
286 print ' {entry} = {lvalue};'.format(**locals())
287 print ' if (retrace::verbosity >= 2) {'
288 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
292 def visitBlob(self, blob, lvalue, rvalue):
295 def visitString(self, string, lvalue, rvalue):
300 def visitStruct(self, struct, lvalue, rvalue):
301 tmp = '__s_' + struct.tag + '_' + str(self.seq)
304 print ' const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
305 print ' assert(%s);' % (tmp,)
306 print ' (void)%s;' % (tmp,)
307 for i in range(len(struct.members)):
308 member_type, member_name = struct.members[i]
309 self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
311 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
312 self.visit(polymorphic.defaultType, lvalue, rvalue)
317 def retraceFunction(self, function):
318 print 'static void retrace_%s(trace::Call &call) {' % function.name
319 self.retraceFunctionBody(function)
323 def retraceInterfaceMethod(self, interface, method):
324 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, method.name)
325 self.retraceInterfaceMethodBody(interface, method)
329 def retraceFunctionBody(self, function):
330 if not function.sideeffects:
334 self.deserializeArgs(function)
336 self.invokeFunction(function)
338 self.swizzleValues(function)
340 def retraceInterfaceMethodBody(self, interface, method):
341 if not method.sideeffects:
345 self.deserializeThisPointer(interface)
347 self.deserializeArgs(method)
349 self.invokeInterfaceMethod(interface, method)
351 self.swizzleValues(method)
353 def deserializeThisPointer(self, interface):
354 print r' %s *_this;' % (interface.name,)
355 print r' _this = static_cast<%s *>(_obj_map[call.arg(0).toUIntPtr()]);' % (interface.name,)
356 print r' if (!_this) {'
357 print r' retrace::warning(call) << "NULL this pointer\n";'
361 def deserializeArgs(self, function):
362 print ' retrace::ScopedAllocator _allocator;'
363 print ' (void)_allocator;'
365 for arg in function.args:
366 arg_type = MutableRebuilder().visit(arg.type)
367 print ' %s %s;' % (arg_type, arg.name)
368 rvalue = 'call.arg(%u)' % (arg.index,)
371 self.extractArg(function, arg, arg_type, lvalue, rvalue)
372 except NotImplementedError:
374 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
379 self.failFunction(function)
380 if function.name[-1].islower():
381 sys.stderr.write('warning: unsupported %s call\n' % function.name)
384 def swizzleValues(self, function):
385 for arg in function.args:
387 arg_type = MutableRebuilder().visit(arg.type)
388 rvalue = 'call.arg(%u)' % (arg.index,)
391 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
392 except NotImplementedError:
393 print ' // XXX: %s' % arg.name
394 if function.type is not stdapi.Void:
398 self.regiterSwizzledValue(function.type, lvalue, rvalue)
399 except NotImplementedError:
401 print ' // XXX: result'
403 def failFunction(self, function):
404 print ' if (retrace::verbosity >= 0) {'
405 print ' retrace::unsupported(call);'
409 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
410 ValueAllocator().visit(arg_type, lvalue, rvalue)
412 ValueDeserializer().visit(arg_type, lvalue, rvalue)
414 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
416 ValueAllocator().visit(arg_type, lvalue, rvalue)
417 except NotImplementedError:
419 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
421 def regiterSwizzledValue(self, type, lvalue, rvalue):
422 visitor = SwizzledValueRegistrator()
423 visitor.visit(type, lvalue, rvalue)
425 def invokeFunction(self, function):
426 arg_names = ", ".join(function.argNames())
427 if function.type is not stdapi.Void:
428 print ' %s __result;' % (function.type)
429 print ' __result = %s(%s);' % (function.name, arg_names)
430 print ' (void)__result;'
432 print ' %s(%s);' % (function.name, arg_names)
434 def invokeInterfaceMethod(self, interface, method):
435 arg_names = ", ".join(method.argNames())
436 if method.type is not stdapi.Void:
437 print ' %s __result;' % (method.type)
438 print ' __result = _this->%s(%s);' % (method.name, arg_names)
439 print ' (void)__result;'
441 print ' _this->%s(%s);' % (method.name, arg_names)
443 def filterFunction(self, function):
446 table_name = 'retrace::callbacks'
448 def retraceApi(self, api):
450 print '#include "os_time.hpp"'
451 print '#include "trace_parser.hpp"'
452 print '#include "retrace.hpp"'
455 types = api.getAllTypes()
456 handles = [type for type in types if isinstance(type, stdapi.Handle)]
458 for handle in handles:
459 if handle.name not in handle_names:
460 if handle.key is None:
461 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
463 key_name, key_type = handle.key
464 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
465 handle_names.add(handle.name)
468 print 'static std::map<unsigned long long, void *> _obj_map;'
471 functions = filter(self.filterFunction, api.functions)
472 for function in functions:
473 self.retraceFunction(function)
474 interfaces = api.getAllInterfaces()
475 for interface in interfaces:
476 for method in interface.iterMethods():
477 self.retraceInterfaceMethod(interface, method)
479 print 'const retrace::Entry %s[] = {' % self.table_name
480 for function in functions:
481 print ' {"%s", &retrace_%s},' % (function.name, function.name)
482 for interface in interfaces:
483 for method in interface.iterMethods():
484 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
485 print ' {NULL, NULL}'