]> git.cworth.org Git - apitrace/blob - retrace.py
90a44140f27dc1d3e3f8f9b4780c40dfc052d6ef
[apitrace] / retrace.py
1 ##########################################################################
2 #
3 # Copyright 2010 VMware, Inc.
4 # All Rights Reserved.
5 #
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:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
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
22 # THE SOFTWARE.
23 #
24 ##########################################################################/
25
26
27 """Generic retracing code generator."""
28
29
30 import sys
31
32 import specs.stdapi as stdapi
33 import specs.glapi as glapi
34
35
36 class ConstRemover(stdapi.Rebuilder):
37
38     def visit_const(self, const):
39         return const.type
40
41     def visit_opaque(self, opaque):
42         return opaque
43
44
45 def handle_entry(handle, value):
46     if handle.key is None:
47         return "__%s_map[%s]" % (handle.name, value)
48     else:
49         key_name, key_type = handle.key
50         return "__%s_map[%s][%s]" % (handle.name, key_name, value)
51
52
53 class ValueExtractor(stdapi.Visitor):
54
55     def visit_literal(self, literal, lvalue, rvalue):
56         #if literal.format in ('Bool', 'UInt'):
57         print '    %s = (%s).to%s();' % (lvalue, rvalue, literal.format)
58
59     def visit_const(self, const, lvalue, rvalue):
60         self.visit(const.type, lvalue, rvalue)
61
62     def visit_alias(self, alias, lvalue, rvalue):
63         self.visit(alias.type, lvalue, rvalue)
64     
65     def visit_enum(self, enum, lvalue, rvalue):
66         print '    %s = (%s).toSInt();' % (lvalue, rvalue)
67
68     def visit_bitmask(self, bitmask, lvalue, rvalue):
69         self.visit(bitmask.type, lvalue, rvalue)
70
71     def visit_array(self, array, lvalue, rvalue):
72         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
73         print '    if (__a%s) {' % (array.id)
74         length = '__a%s->values.size()' % array.id
75         print '        %s = new %s[%s];' % (lvalue, array.type, length)
76         index = '__j' + array.id
77         print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
78         try:
79             self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
80         finally:
81             print '        }'
82             print '    } else {'
83             print '        %s = NULL;' % lvalue
84             print '    }'
85     
86     def visit_pointer(self, pointer, lvalue, rvalue):
87         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
88         print '    if (__a%s) {' % (pointer.id)
89         print '        %s = new %s;' % (lvalue, pointer.type)
90         try:
91             self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
92         finally:
93             print '    } else {'
94             print '        %s = NULL;' % lvalue
95             print '    }'
96
97     def visit_handle(self, handle, lvalue, rvalue):
98         OpaqueValueExtractor().visit(handle.type, lvalue, rvalue);
99         new_lvalue = handle_entry(handle, lvalue)
100         print '    if (retrace::verbosity >= 2) {'
101         print '        std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
102         print '    }'
103         print '    %s = %s;' % (lvalue, new_lvalue)
104     
105     def visit_blob(self, blob, lvalue, rvalue):
106         print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
107     
108     def visit_string(self, string, lvalue, rvalue):
109         print '    %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
110
111
112 class OpaqueValueExtractor(ValueExtractor):
113     '''Value extractor that also understands opaque values.
114
115     Normally opaque values can't be retraced, unless they are being extracted
116     in the context of handles.'''
117
118     def visit_opaque(self, opaque, lvalue, rvalue):
119         print '    %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
120
121
122 class ValueWrapper(stdapi.Visitor):
123
124     def visit_literal(self, literal, lvalue, rvalue):
125         pass
126
127     def visit_alias(self, alias, lvalue, rvalue):
128         self.visit(alias.type, lvalue, rvalue)
129     
130     def visit_enum(self, enum, lvalue, rvalue):
131         pass
132
133     def visit_bitmask(self, bitmask, lvalue, rvalue):
134         pass
135
136     def visit_array(self, array, lvalue, rvalue):
137         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
138         print '    if (__a%s) {' % (array.id)
139         length = '__a%s->values.size()' % array.id
140         index = '__j' + array.id
141         print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
142         try:
143             self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
144         finally:
145             print '        }'
146             print '    }'
147     
148     def visit_pointer(self, pointer, lvalue, rvalue):
149         print '    const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
150         print '    if (__a%s) {' % (pointer.id)
151         try:
152             self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
153         finally:
154             print '    }'
155     
156     def visit_handle(self, handle, lvalue, rvalue):
157         print '    %s __orig_result;' % handle.type
158         OpaqueValueExtractor().visit(handle.type, '__orig_result', rvalue);
159         if handle.range is None:
160             rvalue = "__orig_result"
161             entry = handle_entry(handle, rvalue) 
162             print "    %s = %s;" % (entry, lvalue)
163             print '    if (retrace::verbosity >= 2) {'
164             print '        std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
165             print '    }'
166         else:
167             i = '__h' + handle.id
168             lvalue = "%s + %s" % (lvalue, i)
169             rvalue = "__orig_result + %s" % (i,)
170             entry = handle_entry(handle, rvalue) 
171             print '    for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
172             print '        {entry} = {lvalue};'.format(**locals())
173             print '        if (retrace::verbosity >= 2) {'
174             print '            std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
175             print '        }'
176             print '    }'
177     
178     def visit_blob(self, blob, lvalue, rvalue):
179         pass
180     
181     def visit_string(self, string, lvalue, rvalue):
182         pass
183
184
185 class Retracer:
186
187     def retrace_function(self, function):
188         print 'static void retrace_%s(Trace::Call &call) {' % function.name
189         self.retrace_function_body(function)
190         print '}'
191         print
192
193     def retrace_function_body(self, function):
194         if not function.sideeffects:
195             print '    (void)call;'
196             return
197
198         success = True
199         for arg in function.args:
200             arg_type = ConstRemover().visit(arg.type)
201             #print '    // %s ->  %s' % (arg.type, arg_type)
202             print '    %s %s;' % (arg_type, arg.name)
203             rvalue = 'call.arg(%u)' % (arg.index,)
204             lvalue = arg.name
205             try:
206                 self.extract_arg(function, arg, arg_type, lvalue, rvalue)
207             except NotImplementedError:
208                 success = False
209                 print '    %s = 0; // FIXME' % arg.name
210         if not success:
211             print '    if (1) {'
212             self.fail_function(function)
213             print '    }'
214         self.call_function(function)
215         for arg in function.args:
216             if arg.output:
217                 arg_type = ConstRemover().visit(arg.type)
218                 rvalue = 'call.arg(%u)' % (arg.index,)
219                 lvalue = arg.name
220                 try:
221                     ValueWrapper().visit(arg_type, lvalue, rvalue)
222                 except NotImplementedError:
223                     print '    // XXX: %s' % arg.name
224         if function.type is not stdapi.Void:
225             rvalue = '*call.ret'
226             lvalue = '__result'
227             try:
228                 ValueWrapper().visit(function.type, lvalue, rvalue)
229             except NotImplementedError:
230                 print '    // XXX: result'
231         if not success:
232             if function.name[-1].islower():
233                 sys.stderr.write('warning: unsupported %s call\n' % function.name)
234
235     def fail_function(self, function):
236         print '    if (retrace::verbosity >= 0) {'
237         print '        retrace::unsupported(call);'
238         print '    }'
239         print '    return;'
240
241     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
242         ValueExtractor().visit(arg_type, lvalue, rvalue)
243     
244     def extract_opaque_arg(self, function, arg, arg_type, lvalue, rvalue):
245         OpaqueValueExtractor().visit(arg_type, lvalue, rvalue)
246
247     def call_function(self, function):
248         arg_names = ", ".join([arg.name for arg in function.args])
249         if function.type is not stdapi.Void:
250             print '    %s __result;' % (function.type)
251             print '    __result = %s(%s);' % (function.name, arg_names)
252             print '    (void)__result;'
253         else:
254             print '    %s(%s);' % (function.name, arg_names)
255
256     def filter_function(self, function):
257         return True
258
259     table_name = 'retrace::callbacks'
260
261     def retrace_functions(self, functions):
262         functions = filter(self.filter_function, functions)
263
264         for function in functions:
265             self.retrace_function(function)
266
267         print 'const retrace::Entry %s[] = {' % self.table_name
268         for function in functions:
269             print '    {"%s", &retrace_%s},' % (function.name, function.name)
270         print '    {NULL, NULL}'
271         print '};'
272         print
273
274
275     def retrace_api(self, api):
276
277         print '#include "trace_parser.hpp"'
278         print '#include "retrace.hpp"'
279         print
280
281         types = api.all_types()
282         handles = [type for type in types if isinstance(type, stdapi.Handle)]
283         handle_names = set()
284         for handle in handles:
285             if handle.name not in handle_names:
286                 if handle.key is None:
287                     print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
288                 else:
289                     key_name, key_type = handle.key
290                     print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
291                 handle_names.add(handle.name)
292         print
293
294         self.retrace_functions(api.functions)
295