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