]> git.cworth.org Git - apitrace/blob - retrace.py
Fix a crash when loading multiple frames at once.
[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 '        std::cerr << "warning: unsupported call %s\\n";' % function.name
232         print '    return;'
233
234     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
235         ValueExtractor().visit(arg_type, lvalue, rvalue)
236     
237     def extract_opaque_arg(self, function, arg, arg_type, lvalue, rvalue):
238         OpaqueValueExtractor().visit(arg_type, lvalue, rvalue)
239
240     def call_function(self, function):
241         arg_names = ", ".join([arg.name for arg in function.args])
242         if function.type is not stdapi.Void:
243             print '    %s __result;' % (function.type)
244             print '    __result = %s(%s);' % (function.name, arg_names)
245             print '    (void)__result;'
246         else:
247             print '    %s(%s);' % (function.name, arg_names)
248
249     def filter_function(self, function):
250         return True
251
252     table_name = 'retrace::callbacks'
253
254     def retrace_functions(self, functions):
255         functions = filter(self.filter_function, functions)
256
257         for function in functions:
258             self.retrace_function(function)
259
260         print 'const retrace::Entry %s[] = {' % self.table_name
261         for function in functions:
262             print '    {"%s", &retrace_%s},' % (function.name, function.name)
263         print '    {NULL, NULL}'
264         print '};'
265         print
266
267
268     def retrace_api(self, api):
269
270         print '#include "trace_parser.hpp"'
271         print '#include "retrace.hpp"'
272         print
273
274         types = api.all_types()
275         handles = [type for type in types if isinstance(type, stdapi.Handle)]
276         handle_names = set()
277         for handle in handles:
278             if handle.name not in handle_names:
279                 if handle.key is None:
280                     print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
281                 else:
282                     key_name, key_type = handle.key
283                     print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
284                 handle_names.add(handle.name)
285         print
286
287         self.retrace_functions(api.functions)
288