blob: 27d0afe8879c94e6bb013ee34e4b33d9a5c7159b [file] [log] [blame]
José Fonsecae0e61402010-11-25 15:03:23 +00001##########################################################################
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
José Fonseca4a826ed2010-11-30 16:58:22 +000027"""Generic retracing code generator."""
28
José Fonsecae0e61402010-11-25 15:03:23 +000029import stdapi
30import glapi
José Fonseca522b7442010-11-27 15:30:40 +000031from codegen import *
José Fonsecae0e61402010-11-25 15:03:23 +000032
33
34class ConstRemover(stdapi.Rebuilder):
35
36 def visit_const(self, const):
37 return const.type
38
39 def visit_opaque(self, opaque):
José Fonsecaf01b7f52011-04-20 21:09:28 +010040 return opaque
José Fonsecae0e61402010-11-25 15:03:23 +000041
42
José Fonseca8a844ae2010-12-06 18:50:52 +000043def 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
José Fonsecae0e61402010-11-25 15:03:23 +000051class ValueExtractor(stdapi.Visitor):
52
53 def visit_literal(self, literal, lvalue, rvalue):
54 if literal.format == 'Bool':
55 print ' %s = static_cast<bool>(%s);' % (lvalue, rvalue)
56 else:
57 print ' %s = %s;' % (lvalue, rvalue)
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;' % (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
José Fonsecadbaae492011-04-21 09:28:10 +010077 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +000078 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):
José Fonsecaa10af892011-04-11 09:10:55 +010098 OpaqueValueExtractor().visit(handle.type, lvalue, rvalue);
99 new_lvalue = handle_entry(handle, lvalue)
José Fonseca32871ed2011-04-10 13:40:52 +0100100 print ' if (retrace::verbosity >= 2)'
José Fonsecaa10af892011-04-11 09:10:55 +0100101 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
102 print ' %s = %s;' % (lvalue, new_lvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000103
104 def visit_blob(self, blob, lvalue, rvalue):
105 print ' %s = static_cast<%s>((%s).blob());' % (lvalue, blob, rvalue)
106
107 def visit_string(self, string, lvalue, rvalue):
108 print ' %s = (%s)((%s).string());' % (lvalue, string.expr, rvalue)
109
110
José Fonsecaa10af892011-04-11 09:10:55 +0100111class 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>((%s).blob());' % (lvalue, opaque, rvalue)
119
José Fonsecae0e61402010-11-25 15:03:23 +0000120
121class 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.id, rvalue)
137 print ' if (__a%s) {' % (array.id)
138 length = '__a%s->values.size()' % array.id
139 index = '__j' + array.id
José Fonsecadbaae492011-04-21 09:28:10 +0100140 print ' for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
José Fonsecae0e61402010-11-25 15:03:23 +0000141 try:
142 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, 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.id, rvalue)
149 print ' if (__a%s) {' % (pointer.id)
150 try:
151 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
152 finally:
153 print ' }'
154
José Fonsecae0e61402010-11-25 15:03:23 +0000155 def visit_handle(self, handle, lvalue, rvalue):
José Fonsecaa10af892011-04-11 09:10:55 +0100156 print ' %s __orig_result;' % handle.type
157 OpaqueValueExtractor().visit(handle.type, '__orig_result', rvalue);
José Fonsecad922e1d2010-11-25 17:14:02 +0000158 if handle.range is None:
José Fonsecaa10af892011-04-11 09:10:55 +0100159 rvalue = "__orig_result"
José Fonseca8a844ae2010-12-06 18:50:52 +0000160 entry = handle_entry(handle, rvalue)
161 print " %s = %s;" % (entry, lvalue)
José Fonseca32871ed2011-04-10 13:40:52 +0100162 print ' if (retrace::verbosity >= 2)'
José Fonseca8a844ae2010-12-06 18:50:52 +0000163 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
José Fonsecad922e1d2010-11-25 17:14:02 +0000164 else:
165 i = '__h' + handle.id
José Fonseca8a844ae2010-12-06 18:50:52 +0000166 lvalue = "%s + %s" % (lvalue, i)
José Fonsecaa10af892011-04-11 09:10:55 +0100167 rvalue = "__orig_result + %s" % (i,)
José Fonseca8a844ae2010-12-06 18:50:52 +0000168 entry = handle_entry(handle, rvalue)
José Fonsecadbaae492011-04-21 09:28:10 +0100169 print ' for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
José Fonseca8a844ae2010-12-06 18:50:52 +0000170 print ' {entry} = {lvalue};'.format(**locals())
José Fonseca32871ed2011-04-10 13:40:52 +0100171 print ' if (retrace::verbosity >= 2)'
José Fonseca8a844ae2010-12-06 18:50:52 +0000172 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
José Fonsecad922e1d2010-11-25 17:14:02 +0000173 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000174
175 def visit_blob(self, blob, lvalue, rvalue):
176 pass
177
178 def visit_string(self, string, lvalue, rvalue):
179 pass
180
181
José Fonsecae0e61402010-11-25 15:03:23 +0000182class Retracer:
183
184 def retrace_function(self, function):
185 print 'static void retrace_%s(Trace::Call &call) {' % function.name
José Fonseca62212972011-03-23 13:22:55 +0000186 self.retrace_function_body(function)
187 print '}'
188 print
189
190 def retrace_function_body(self, function):
José Fonsecae0e61402010-11-25 15:03:23 +0000191 success = True
192 for arg in function.args:
193 arg_type = ConstRemover().visit(arg.type)
194 #print ' // %s -> %s' % (arg.type, arg_type)
195 print ' %s %s;' % (arg_type, arg.name)
196 rvalue = 'call.arg(%u)' % (arg.index,)
197 lvalue = arg.name
198 try:
José Fonsecadacd8dd2010-11-25 17:50:26 +0000199 self.extract_arg(function, arg, arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000200 except NotImplementedError:
201 success = False
202 print ' %s = 0; // FIXME' % arg.name
203 if not success:
José Fonsecafa15d332010-11-25 20:22:39 +0000204 self.fail_function(function)
205 self.call_function(function)
José Fonsecae0e61402010-11-25 15:03:23 +0000206 for arg in function.args:
207 if arg.output:
208 arg_type = ConstRemover().visit(arg.type)
209 rvalue = 'call.arg(%u)' % (arg.index,)
210 lvalue = arg.name
211 try:
212 ValueWrapper().visit(arg_type, lvalue, rvalue)
213 except NotImplementedError:
214 print ' // FIXME: %s' % arg.name
215 if function.type is not stdapi.Void:
216 rvalue = '*call.ret'
217 lvalue = '__result'
218 try:
219 ValueWrapper().visit(function.type, lvalue, rvalue)
220 except NotImplementedError:
221 print ' // FIXME: result'
José Fonsecae0e61402010-11-25 15:03:23 +0000222
José Fonsecafa15d332010-11-25 20:22:39 +0000223 def fail_function(self, function):
José Fonseca32871ed2011-04-10 13:40:52 +0100224 print ' if (retrace::verbosity >= 0)'
José Fonseca5e687162011-02-09 15:11:12 +0000225 print ' std::cerr << "warning: unsupported call %s\\n";' % function.name
José Fonsecafa15d332010-11-25 20:22:39 +0000226 print ' return;'
227
José Fonsecadacd8dd2010-11-25 17:50:26 +0000228 def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
229 ValueExtractor().visit(arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000230
José Fonsecafa15d332010-11-25 20:22:39 +0000231 def call_function(self, function):
232 arg_names = ", ".join([arg.name for arg in function.args])
233 if function.type is not stdapi.Void:
234 print ' %s __result;' % (function.type)
235 print ' __result = %s(%s);' % (function.name, arg_names)
236 else:
237 print ' %s(%s);' % (function.name, arg_names)
238
José Fonseca4441baf2010-11-25 19:55:27 +0000239 def filter_function(self, function):
240 return True
241
José Fonsecae0e61402010-11-25 15:03:23 +0000242 def retrace_functions(self, functions):
José Fonseca4441baf2010-11-25 19:55:27 +0000243 functions = filter(self.filter_function, functions)
244
José Fonsecae0e61402010-11-25 15:03:23 +0000245 for function in functions:
246 if function.sideeffects:
247 self.retrace_function(function)
248
José Fonseca32871ed2011-04-10 13:40:52 +0100249 print 'bool retrace::retrace_call(Trace::Call &call) {'
José Fonseca522b7442010-11-27 15:30:40 +0000250 print ' const char *name = call.name().c_str();'
José Fonsecae0e61402010-11-25 15:03:23 +0000251 print
José Fonseca32871ed2011-04-10 13:40:52 +0100252 print ' if (retrace::verbosity >= 1) {'
José Fonsecae0e61402010-11-25 15:03:23 +0000253 print ' std::cout << call;'
254 print ' std::cout.flush();'
255 print ' };'
256 print
José Fonseca522b7442010-11-27 15:30:40 +0000257
258 func_dict = dict([(function.name, function) for function in functions])
259
260 def handle_case(function_name):
261 function = func_dict[function_name]
José Fonsecae0e61402010-11-25 15:03:23 +0000262 if function.sideeffects:
José Fonsecae0e61402010-11-25 15:03:23 +0000263 print ' retrace_%s(call);' % function.name
José Fonseca522b7442010-11-27 15:30:40 +0000264 print ' return true;'
265
266 string_switch('name', func_dict.keys(), handle_case)
267
José Fonseca32871ed2011-04-10 13:40:52 +0100268 print ' if (retrace::verbosity >= 0)'
Zack Rusin20bc32d2011-04-19 16:44:46 -0400269 print ' std::cerr << call.no << ": warning: unknown call " << call.name() << "\\n";'
José Fonsecae0e61402010-11-25 15:03:23 +0000270 print ' return false;'
271 print '}'
272 print
273
274
275 def retrace_api(self, api):
276
277 print '#include "trace_parser.hpp"'
José Fonseca91343f52011-04-01 08:37:06 +0100278 print '#include "retrace.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000279 print
280
281 types = api.all_types()
282 handles = [type for type in types if isinstance(type, stdapi.Handle)]
José Fonsecad922e1d2010-11-25 17:14:02 +0000283 handle_names = set()
José Fonsecae0e61402010-11-25 15:03:23 +0000284 for handle in handles:
José Fonsecad922e1d2010-11-25 17:14:02 +0000285 if handle.name not in handle_names:
José Fonseca8a844ae2010-12-06 18:50:52 +0000286 if handle.key is None:
José Fonseca91343f52011-04-01 08:37:06 +0100287 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
José Fonseca8a844ae2010-12-06 18:50:52 +0000288 else:
289 key_name, key_type = handle.key
José Fonseca91343f52011-04-01 08:37:06 +0100290 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
José Fonsecad922e1d2010-11-25 17:14:02 +0000291 handle_names.add(handle.name)
José Fonsecae0e61402010-11-25 15:03:23 +0000292 print
293
José Fonsecae0e61402010-11-25 15:03:23 +0000294 self.retrace_functions(api.functions)
295