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