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 assert function.sideeffects
332 self.deserializeArgs(function)
334 self.invokeFunction(function)
336 self.swizzleValues(function)
338 def retraceInterfaceMethodBody(self, interface, method):
339 assert method.sideeffects
341 self.deserializeThisPointer(interface)
343 self.deserializeArgs(method)
345 self.invokeInterfaceMethod(interface, method)
347 self.swizzleValues(method)
349 def deserializeThisPointer(self, interface):
350 print r' %s *_this;' % (interface.name,)
351 print r' _this = static_cast<%s *>(_obj_map[call.arg(0).toUIntPtr()]);' % (interface.name,)
352 print r' if (!_this) {'
353 print r' retrace::warning(call) << "NULL this pointer\n";'
357 def deserializeArgs(self, function):
358 print ' retrace::ScopedAllocator _allocator;'
359 print ' (void)_allocator;'
361 for arg in function.args:
362 arg_type = MutableRebuilder().visit(arg.type)
363 print ' %s %s;' % (arg_type, arg.name)
364 rvalue = 'call.arg(%u)' % (arg.index,)
367 self.extractArg(function, arg, arg_type, lvalue, rvalue)
368 except NotImplementedError:
370 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
375 self.failFunction(function)
376 if function.name[-1].islower():
377 sys.stderr.write('warning: unsupported %s call\n' % function.name)
380 def swizzleValues(self, function):
381 for arg in function.args:
383 arg_type = MutableRebuilder().visit(arg.type)
384 rvalue = 'call.arg(%u)' % (arg.index,)
387 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
388 except NotImplementedError:
389 print ' // XXX: %s' % arg.name
390 if function.type is not stdapi.Void:
394 self.regiterSwizzledValue(function.type, lvalue, rvalue)
395 except NotImplementedError:
397 print ' // XXX: result'
399 def failFunction(self, function):
400 print ' if (retrace::verbosity >= 0) {'
401 print ' retrace::unsupported(call);'
405 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
406 ValueAllocator().visit(arg_type, lvalue, rvalue)
408 ValueDeserializer().visit(arg_type, lvalue, rvalue)
410 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
412 ValueAllocator().visit(arg_type, lvalue, rvalue)
413 except NotImplementedError:
415 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
417 def regiterSwizzledValue(self, type, lvalue, rvalue):
418 visitor = SwizzledValueRegistrator()
419 visitor.visit(type, lvalue, rvalue)
421 def invokeFunction(self, function):
422 arg_names = ", ".join(function.argNames())
423 if function.type is not stdapi.Void:
424 print ' %s __result;' % (function.type)
425 print ' __result = %s(%s);' % (function.name, arg_names)
426 print ' (void)__result;'
428 print ' %s(%s);' % (function.name, arg_names)
430 def invokeInterfaceMethod(self, interface, method):
431 arg_names = ", ".join(method.argNames())
432 if method.type is not stdapi.Void:
433 print ' %s __result;' % (method.type)
434 print ' __result = _this->%s(%s);' % (method.name, arg_names)
435 print ' (void)__result;'
437 print ' _this->%s(%s);' % (method.name, arg_names)
439 def filterFunction(self, function):
442 table_name = 'retrace::callbacks'
444 def retraceApi(self, api):
446 print '#include "os_time.hpp"'
447 print '#include "trace_parser.hpp"'
448 print '#include "retrace.hpp"'
451 types = api.getAllTypes()
452 handles = [type for type in types if isinstance(type, stdapi.Handle)]
454 for handle in handles:
455 if handle.name not in handle_names:
456 if handle.key is None:
457 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
459 key_name, key_type = handle.key
460 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
461 handle_names.add(handle.name)
464 print 'static std::map<unsigned long long, void *> _obj_map;'
467 functions = filter(self.filterFunction, api.functions)
468 for function in functions:
469 if function.sideeffects:
470 self.retraceFunction(function)
471 interfaces = api.getAllInterfaces()
472 for interface in interfaces:
473 for method in interface.iterMethods():
474 if method.sideeffects:
475 self.retraceInterfaceMethod(interface, method)
477 print 'const retrace::Entry %s[] = {' % self.table_name
478 for function in functions:
479 if function.sideeffects:
480 print ' {"%s", &retrace_%s},' % (function.name, function.name)
482 print ' {"%s", &retrace::ignore},' % (function.name,)
483 for interface in interfaces:
484 for method in interface.iterMethods():
485 if method.sideeffects:
486 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
488 print ' {"%s::%s", &retrace::ignore},' % (interface.name, method.name)
489 print ' {NULL, NULL}'