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 ValueDeserializer(stdapi.Visitor):
69 def visitLiteral(self, literal, lvalue, rvalue):
70 print ' %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
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):
79 print ' %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
81 def visitBitmask(self, bitmask, lvalue, rvalue):
82 self.visit(bitmask.type, lvalue, rvalue)
86 def visitArray(self, array, lvalue, rvalue):
87 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
88 length = '__a%s->values.size()' % array.tag
89 allocated = self.allocated
91 print ' if (__a%s) {' % (array.tag)
92 print ' %s = _allocator.alloc<%s>(%s);' % (lvalue, array.type, length)
94 index = '__j' + array.tag
95 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
97 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
102 print ' %s = NULL;' % lvalue
105 def visitPointer(self, pointer, lvalue, rvalue):
106 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
107 allocated = self.allocated
109 print ' if (__a%s) {' % (pointer.tag)
110 print ' %s = _allocator.alloc<%s>();' % (lvalue, pointer.type)
111 self.allocated = True
113 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
117 print ' %s = NULL;' % lvalue
120 def visitIntPointer(self, pointer, lvalue, rvalue):
121 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
123 def visitObjPointer(self, pointer, lvalue, rvalue):
124 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
126 def visitLinearPointer(self, pointer, lvalue, rvalue):
127 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
129 def visitReference(self, reference, lvalue, rvalue):
130 self.visit(reference.type, lvalue, rvalue);
132 def visitHandle(self, handle, lvalue, rvalue):
133 #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
134 self.visit(handle.type, lvalue, rvalue);
135 new_lvalue = lookupHandle(handle, lvalue)
136 print ' if (retrace::verbosity >= 2) {'
137 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
139 print ' %s = %s;' % (lvalue, new_lvalue)
141 def visitBlob(self, blob, lvalue, rvalue):
142 print ' %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
144 def visitString(self, string, lvalue, rvalue):
145 print ' %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
149 def visitStruct(self, struct, lvalue, rvalue):
150 tmp = '__s_' + struct.tag + '_' + str(self.seq)
153 print ' const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
154 print ' assert(%s);' % (tmp)
155 self.allocated = True
156 for i in range(len(struct.members)):
157 member_type, member_name = struct.members[i]
158 self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
161 class OpaqueValueDeserializer(ValueDeserializer):
162 '''Value extractor that also understands opaque values.
164 Normally opaque values can't be retraced, unless they are being extracted
165 in the context of handles.'''
167 def visitOpaque(self, opaque, lvalue, rvalue):
168 print ' %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
171 class SwizzledValueRegistrator(stdapi.Visitor):
172 '''Type visitor which will register (un)swizzled value pairs, to later be
175 def visitLiteral(self, literal, lvalue, rvalue):
178 def visitAlias(self, alias, lvalue, rvalue):
179 self.visit(alias.type, lvalue, rvalue)
181 def visitEnum(self, enum, lvalue, rvalue):
184 def visitBitmask(self, bitmask, lvalue, rvalue):
187 def visitArray(self, array, lvalue, rvalue):
188 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
189 print ' if (__a%s) {' % (array.tag)
190 length = '__a%s->values.size()' % array.tag
191 index = '__j' + array.tag
192 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
194 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
199 def visitPointer(self, pointer, lvalue, rvalue):
200 print ' const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
201 print ' if (__a%s) {' % (pointer.tag)
203 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
207 def visitIntPointer(self, pointer, lvalue, rvalue):
210 def visitObjPointer(self, pointer, lvalue, rvalue):
211 print r' _obj_map[(%s).toUIntPtr()] = %s;' % (rvalue, lvalue)
213 def visitLinearPointer(self, pointer, lvalue, rvalue):
214 assert pointer.size is not None
215 if pointer.size is not None:
216 print r' retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
218 def visitReference(self, reference, lvalue, rvalue):
221 def visitHandle(self, handle, lvalue, rvalue):
222 print ' %s __orig_result;' % handle.type
223 OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
224 if handle.range is None:
225 rvalue = "__orig_result"
226 entry = lookupHandle(handle, rvalue)
227 print " %s = %s;" % (entry, lvalue)
228 print ' if (retrace::verbosity >= 2) {'
229 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
232 i = '__h' + handle.tag
233 lvalue = "%s + %s" % (lvalue, i)
234 rvalue = "__orig_result + %s" % (i,)
235 entry = lookupHandle(handle, rvalue)
236 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
237 print ' {entry} = {lvalue};'.format(**locals())
238 print ' if (retrace::verbosity >= 2) {'
239 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
243 def visitBlob(self, blob, lvalue, rvalue):
246 def visitString(self, string, lvalue, rvalue):
252 def retraceFunction(self, function):
253 print 'static void retrace_%s(trace::Call &call) {' % function.name
254 self.retraceFunctionBody(function)
258 def retraceInterfaceMethod(self, interface, method):
259 print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, method.name)
260 self.retraceInterfaceMethodBody(interface, method)
264 def retraceFunctionBody(self, function):
265 if not function.sideeffects:
269 self.deserializeArgs(function)
271 self.invokeFunction(function)
273 self.swizzleValues(function)
275 def retraceInterfaceMethodBody(self, interface, method):
276 if not method.sideeffects:
280 self.deserializeThisPointer(interface)
282 self.deserializeArgs(method)
284 self.invokeInterfaceMethod(interface, method)
286 self.swizzleValues(method)
288 def deserializeThisPointer(self, interface):
289 print ' %s *_this;' % (interface.name,)
290 print ' _this = static_cast<%s *>(_obj_map[call.arg(0).toUIntPtr()]);' % (interface.name,)
292 def deserializeArgs(self, function):
293 print ' retrace::ScopedAllocator _allocator;'
294 print ' (void)_allocator;'
296 for arg in function.args:
297 arg_type = MutableRebuilder().visit(arg.type)
298 #print ' // %s -> %s' % (arg.type, arg_type)
299 print ' %s %s;' % (arg_type, arg.name)
300 rvalue = 'call.arg(%u)' % (arg.index,)
303 self.extractArg(function, arg, arg_type, lvalue, rvalue)
304 except NotImplementedError:
306 print ' memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
310 self.failFunction(function)
311 if function.name[-1].islower():
312 sys.stderr.write('warning: unsupported %s call\n' % function.name)
315 def swizzleValues(self, function):
316 for arg in function.args:
318 arg_type = MutableRebuilder().visit(arg.type)
319 rvalue = 'call.arg(%u)' % (arg.index,)
322 self.regiterSwizzledValue(arg_type, lvalue, rvalue)
323 except NotImplementedError:
324 print ' // XXX: %s' % arg.name
325 if function.type is not stdapi.Void:
329 self.regiterSwizzledValue(function.type, lvalue, rvalue)
330 except NotImplementedError:
332 print ' // XXX: result'
334 def failFunction(self, function):
335 print ' if (retrace::verbosity >= 0) {'
336 print ' retrace::unsupported(call);'
340 def extractArg(self, function, arg, arg_type, lvalue, rvalue):
341 ValueDeserializer().visit(arg_type, lvalue, rvalue)
343 def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
344 OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
346 def regiterSwizzledValue(self, type, lvalue, rvalue):
347 visitor = SwizzledValueRegistrator()
348 visitor.visit(type, lvalue, rvalue)
350 def invokeFunction(self, function):
351 arg_names = ", ".join(function.argNames())
352 if function.type is not stdapi.Void:
353 print ' %s __result;' % (function.type)
354 print ' __result = %s(%s);' % (function.name, arg_names)
355 print ' (void)__result;'
357 print ' %s(%s);' % (function.name, arg_names)
359 def invokeInterfaceMethod(self, interface, method):
360 arg_names = ", ".join(method.argNames())
361 if method.type is not stdapi.Void:
362 print ' %s __result;' % (method.type)
363 print ' __result = _this->%s(%s);' % (method.name, arg_names)
364 print ' (void)__result;'
366 print ' _this->%s(%s);' % (method.name, arg_names)
368 def filterFunction(self, function):
371 table_name = 'retrace::callbacks'
373 def retraceApi(self, api):
375 print '#include "os_time.hpp"'
376 print '#include "trace_parser.hpp"'
377 print '#include "retrace.hpp"'
380 types = api.getAllTypes()
381 handles = [type for type in types if isinstance(type, stdapi.Handle)]
383 for handle in handles:
384 if handle.name not in handle_names:
385 if handle.key is None:
386 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
388 key_name, key_type = handle.key
389 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
390 handle_names.add(handle.name)
393 print 'static std::map<unsigned long long, void *> _obj_map;'
396 functions = filter(self.filterFunction, api.functions)
397 for function in functions:
398 self.retraceFunction(function)
399 interfaces = api.getAllInterfaces()
400 for interface in interfaces:
401 for method in interface.iterMethods():
402 self.retraceInterfaceMethod(interface, method)
404 print 'const retrace::Entry %s[] = {' % self.table_name
405 for function in functions:
406 print ' {"%s", &retrace_%s},' % (function.name, function.name)
407 for interface in interfaces:
408 for method in interface.iterMethods():
409 print ' {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
410 print ' {NULL, NULL}'