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