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 UnsupportedType(Exception):
40 class MutableRebuilder(stdapi.Rebuilder):
41 '''Type visitor which derives a mutable type.'''
43 def visitConst(self, const):
44 # Strip out const qualifier
47 def visitAlias(self, alias):
48 # Tear the alias on type changes
49 type = self.visit(alias.type)
50 if type is alias.type:
54 def visitReference(self, reference):
55 # Strip out references
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)
117 def visitOpaque(self, opaque, lvalue, rvalue):
121 class ValueDeserializer(stdapi.Visitor):
123 def visitLiteral(self, literal, lvalue, rvalue):
124 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
126 def visitConst(self, const, lvalue, rvalue):
127 self.visit(const.type, lvalue, rvalue)
129 def visitAlias(self, alias, lvalue, rvalue):
130 self.visit(alias.type, lvalue, rvalue)
132 def visitEnum(self, enum, lvalue, rvalue):
133 print ' %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
135 def visitBitmask(self, bitmask, lvalue, rvalue):
136 self.visit(bitmask.type, lvalue, rvalue)
138 def visitArray(self, array, lvalue, rvalue):
140 tmp = '__a_' + array.tag + '_' + str(self.seq)
143 print ' if (%s) {' % (lvalue,)
144 print ' const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
145 length = '%s->values.size()' % (tmp,)
146 index = '__j' + array.tag
147 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
149 self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
154 def visitPointer(self, pointer, lvalue, rvalue):
155 tmp = '__a_' + pointer.tag + '_' + str(self.seq)
158 print ' if (%s) {' % (lvalue,)
159 print ' const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
161 self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
165 def visitIntPointer(self, pointer, lvalue, rvalue):
166 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
168 def visitObjPointer(self, pointer, lvalue, rvalue):
169 old_lvalue = '(%s).toUIntPtr()' % (rvalue,)
170 new_lvalue = '_obj_map[%s]' % (old_lvalue,)
171 print ' if (retrace::verbosity >= 2) {'
172 print ' std::cout << std::hex << "obj 0x" << size_t(%s) << " <- 0x" << size_t(%s) << std::dec <<"\\n";' % (old_lvalue, new_lvalue)
174 print ' %s = static_cast<%s>(%s);' % (lvalue, pointer, new_lvalue)
176 def visitLinearPointer(self, pointer, lvalue, rvalue):
177 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
179 def visitReference(self, reference, lvalue, rvalue):
180 self.visit(reference.type, lvalue, rvalue);
182 def visitHandle(self, handle, lvalue, rvalue):
183 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
184 self.visit(handle.type, lvalue, rvalue);
185 new_lvalue = lookupHandle(handle, lvalue)
186 print ' if (retrace::verbosity >= 2) {'
187 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
189 print ' %s = %s;' % (lvalue, new_lvalue)
191 def visitBlob(self, blob, lvalue, rvalue):
192 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
194 def visitString(self, string, lvalue, rvalue):
195 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
199 def visitStruct(self, struct, lvalue, rvalue):
200 tmp = '__s_' + struct.tag + '_' + str(self.seq)
203 print ' const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
204 print ' assert(%s);' % (tmp)
205 for i in range(len(struct.members)):
206 member_type, member_name = struct.members[i]
207 self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
209 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
210 self.visit(polymorphic.defaultType, lvalue, rvalue)
212 def visitOpaque(self, opaque, lvalue, rvalue):
213 raise UnsupportedType
216 class OpaqueValueDeserializer(ValueDeserializer):
217 '''Value extractor that also understands opaque values.
219 Normally opaque values can't be retraced, unless they are being extracted
220 in the context of handles.'''
222 def visitOpaque(self, opaque, lvalue, rvalue):
223 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
226 class SwizzledValueRegistrator(stdapi.Visitor):
227 '''Type visitor which will register (un)swizzled value pairs, to later be
230 def visitLiteral(self, literal, lvalue, rvalue):
233 def visitAlias(self, alias, lvalue, rvalue):
234 self.visit(alias.type, lvalue, rvalue)
236 def visitEnum(self, enum, lvalue, rvalue):
239 def visitBitmask(self, bitmask, lvalue, rvalue):
242 def visitArray(self, array, lvalue, rvalue):
243 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
244 print ' if (__a%s) {' % (array.tag)
245 length = '__a%s->values.size()' % array.tag
246 index = '__j' + array.tag
247 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
249 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
254 def visitPointer(self, pointer, lvalue, rvalue):
255 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
256 print ' if (__a%s) {' % (pointer.tag)
258 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
262 def visitIntPointer(self, pointer, lvalue, rvalue):
265 def visitObjPointer(self, pointer, lvalue, rvalue):
266 print r' _obj_map[(%s).toUIntPtr()] = %s;' % (rvalue, lvalue)
268 def visitLinearPointer(self, pointer, lvalue, rvalue):
269 assert pointer.size is not None
270 if pointer.size is not None:
271 print r' retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
273 def visitReference(self, reference, lvalue, rvalue):
276 def visitHandle(self, handle, lvalue, rvalue):
277 print ' %s __orig_result;' % handle.type
278 OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
279 if handle.range is None:
280 rvalue = "__orig_result"
281 entry = lookupHandle(handle, rvalue)
282 print " %s = %s;" % (entry, lvalue)
283 print ' if (retrace::verbosity >= 2) {'
284 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
287 i = '__h' + handle.tag
288 lvalue = "%s + %s" % (lvalue, i)
289 rvalue = "__orig_result + %s" % (i,)
290 entry = lookupHandle(handle, rvalue)
291 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
292 print ' {entry} = {lvalue};'.format(**locals())
293 print ' if (retrace::verbosity >= 2) {'
294 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
298 def visitBlob(self, blob, lvalue, rvalue):
301 def visitString(self, string, lvalue, rvalue):
306 def visitStruct(self, struct, lvalue, rvalue):
307 tmp = '__s_' + struct.tag + '_' + str(self.seq)
310 print ' const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
311 print ' assert(%s);' % (tmp,)
312 print ' (void)%s;' % (tmp,)
313 for i in range(len(struct.members)):
314 member_type, member_name = struct.members[i]
315 self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
317 def visitPolymorphic(self, polymorphic, lvalue, rvalue):
318 self.visit(polymorphic.defaultType, lvalue, rvalue)
320 def visitOpaque(self, opaque, lvalue, rvalue):
326 def retraceFunction(self, function):
327 print 'static void retrace_%s(trace::Call &call) {' % function.name
328 self.retraceFunctionBody(function)
332 def retraceInterfaceMethod(self, interface, method):
333 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, method.name)
334 self.retraceInterfaceMethodBody(interface, method)
338 def retraceFunctionBody(self, function):
339 assert function.sideeffects
341 self.deserializeArgs(function)
343 self.invokeFunction(function)
345 self.swizzleValues(function)
347 def retraceInterfaceMethodBody(self, interface, method):
348 assert method.sideeffects
350 self.deserializeThisPointer(interface)
352 self.deserializeArgs(method)
354 self.invokeInterfaceMethod(interface, method)
356 self.swizzleValues(method)
358 def deserializeThisPointer(self, interface):
359 print r' %s *_this;' % (interface.name,)
360 print r' _this = static_cast<%s *>(_obj_map[call.arg(0).toUIntPtr()]);' % (interface.name,)
361 print r' if (!_this) {'
362 print r' retrace::warning(call) << "NULL this pointer\n";'
366 def deserializeArgs(self, function):
367 print ' retrace::ScopedAllocator _allocator;'
368 print ' (void)_allocator;'
370 for arg in function.args:
371 arg_type = MutableRebuilder().visit(arg.type)
372 print ' %s %s;' % (arg_type, arg.name)
373 rvalue = 'call.arg(%u)' % (arg.index,)
376 self.extractArg(function, arg, arg_type, lvalue, rvalue)
377 except UnsupportedType:
379 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
384 self.failFunction(function)
385 if function.name[-1].islower():
386 sys.stderr.write('warning: unsupported %s call\n' % function.name)
389 def swizzleValues(self, function):
390 for arg in function.args:
392 arg_type = MutableRebuilder().visit(arg.type)
393 rvalue = 'call.arg(%u)' % (arg.index,)
396 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
397 except UnsupportedType:
398 print ' // XXX: %s' % arg.name
399 if function.type is not stdapi.Void:
403 self.regiterSwizzledValue(function.type, lvalue, rvalue)
404 except UnsupportedType:
406 print ' // XXX: result'
408 def failFunction(self, function):
409 print ' if (retrace::verbosity >= 0) {'
410 print ' retrace::unsupported(call);'
414 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
415 ValueAllocator().visit(arg_type, lvalue, rvalue)
417 ValueDeserializer().visit(arg_type, lvalue, rvalue)
419 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
421 ValueAllocator().visit(arg_type, lvalue, rvalue)
422 except UnsupportedType:
424 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
426 def regiterSwizzledValue(self, type, lvalue, rvalue):
427 visitor = SwizzledValueRegistrator()
428 visitor.visit(type, lvalue, rvalue)
430 def invokeFunction(self, function):
431 arg_names = ", ".join(function.argNames())
432 if function.type is not stdapi.Void:
433 print ' %s __result;' % (function.type)
434 print ' __result = %s(%s);' % (function.name, arg_names)
435 print ' (void)__result;'
437 print ' %s(%s);' % (function.name, arg_names)
439 def invokeInterfaceMethod(self, interface, method):
440 arg_names = ", ".join(method.argNames())
441 if method.type is not stdapi.Void:
442 print ' %s __result;' % (method.type)
443 print ' __result = _this->%s(%s);' % (method.name, arg_names)
444 print ' (void)__result;'
446 print ' _this->%s(%s);' % (method.name, arg_names)
448 def filterFunction(self, function):
451 table_name = 'retrace::callbacks'
453 def retraceApi(self, api):
455 print '#include "os_time.hpp"'
456 print '#include "trace_parser.hpp"'
457 print '#include "retrace.hpp"'
460 types = api.getAllTypes()
461 handles = [type for type in types if isinstance(type, stdapi.Handle)]
463 for handle in handles:
464 if handle.name not in handle_names:
465 if handle.key is None:
466 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
468 key_name, key_type = handle.key
469 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
470 handle_names.add(handle.name)
473 print 'static std::map<unsigned long long, void *> _obj_map;'
476 functions = filter(self.filterFunction, api.functions)
477 for function in functions:
478 if function.sideeffects:
479 self.retraceFunction(function)
480 interfaces = api.getAllInterfaces()
481 for interface in interfaces:
482 for method in interface.iterMethods():
483 if method.sideeffects:
484 self.retraceInterfaceMethod(interface, method)
486 print 'const retrace::Entry %s[] = {' % self.table_name
487 for function in functions:
488 if function.sideeffects:
489 print ' {"%s", &retrace_%s},' % (function.name, function.name)
491 print ' {"%s", &retrace::ignore},' % (function.name,)
492 for interface in interfaces:
493 for method in interface.iterMethods():
494 if method.sideeffects:
495 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
497 print ' {"%s::%s", &retrace::ignore},' % (interface.name, method.name)
498 print ' {NULL, NULL}'