blob: 3a6c0f9cebfe6bfc7e6705f245834183004e9553 [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):
40 expr = opaque.expr
41 if expr.startswith('const '):
42 expr = expr[6:]
43 return stdapi.Opaque(expr)
44
45
José Fonseca8a844ae2010-12-06 18:50:52 +000046def handle_entry(handle, value):
47 if handle.key is None:
48 return "__%s_map[%s]" % (handle.name, value)
49 else:
50 key_name, key_type = handle.key
51 return "__%s_map[%s][%s]" % (handle.name, key_name, value)
52
53
José Fonsecae0e61402010-11-25 15:03:23 +000054class ValueExtractor(stdapi.Visitor):
55
56 def visit_literal(self, literal, lvalue, rvalue):
57 if literal.format == 'Bool':
58 print ' %s = static_cast<bool>(%s);' % (lvalue, rvalue)
59 else:
60 print ' %s = %s;' % (lvalue, rvalue)
61
62 def visit_const(self, const, lvalue, rvalue):
63 self.visit(const.type, lvalue, rvalue)
64
65 def visit_alias(self, alias, lvalue, rvalue):
66 self.visit(alias.type, lvalue, rvalue)
67
68 def visit_enum(self, enum, lvalue, rvalue):
69 print ' %s = %s;' % (lvalue, rvalue)
70
71 def visit_bitmask(self, bitmask, lvalue, rvalue):
72 self.visit(bitmask.type, lvalue, rvalue)
73
74 def visit_array(self, array, lvalue, rvalue):
75 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
76 print ' if (__a%s) {' % (array.id)
77 length = '__a%s->values.size()' % array.id
78 print ' %s = new %s[%s];' % (lvalue, array.type, length)
79 index = '__j' + array.id
80 print ' for(size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
81 try:
82 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
83 finally:
84 print ' }'
85 print ' } else {'
86 print ' %s = NULL;' % lvalue
87 print ' }'
88
89 def visit_pointer(self, pointer, lvalue, rvalue):
90 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
91 print ' if (__a%s) {' % (pointer.id)
92 print ' %s = new %s;' % (lvalue, pointer.type)
93 try:
94 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
95 finally:
96 print ' } else {'
97 print ' %s = NULL;' % lvalue
98 print ' }'
99
100 def visit_handle(self, handle, lvalue, rvalue):
José Fonsecaa10af892011-04-11 09:10:55 +0100101 OpaqueValueExtractor().visit(handle.type, lvalue, rvalue);
102 new_lvalue = handle_entry(handle, lvalue)
José Fonseca32871ed2011-04-10 13:40:52 +0100103 print ' if (retrace::verbosity >= 2)'
José Fonsecaa10af892011-04-11 09:10:55 +0100104 print ' std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
105 print ' %s = %s;' % (lvalue, new_lvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000106
107 def visit_blob(self, blob, lvalue, rvalue):
108 print ' %s = static_cast<%s>((%s).blob());' % (lvalue, blob, rvalue)
109
110 def visit_string(self, string, lvalue, rvalue):
111 print ' %s = (%s)((%s).string());' % (lvalue, string.expr, rvalue)
112
113
José Fonsecaa10af892011-04-11 09:10:55 +0100114class OpaqueValueExtractor(ValueExtractor):
115 '''Value extractor that also understands opaque values.
116
117 Normally opaque values can't be retraced, unless they are being extracted
118 in the context of handles.'''
119
120 def visit_opaque(self, opaque, lvalue, rvalue):
121 print ' %s = static_cast<%s>((%s).blob());' % (lvalue, opaque, rvalue)
122
José Fonsecae0e61402010-11-25 15:03:23 +0000123
124class ValueWrapper(stdapi.Visitor):
125
126 def visit_literal(self, literal, lvalue, rvalue):
127 pass
128
129 def visit_alias(self, alias, lvalue, rvalue):
130 self.visit(alias.type, lvalue, rvalue)
131
132 def visit_enum(self, enum, lvalue, rvalue):
133 pass
134
135 def visit_bitmask(self, bitmask, lvalue, rvalue):
136 pass
137
138 def visit_array(self, array, lvalue, rvalue):
139 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (array.id, rvalue)
140 print ' if (__a%s) {' % (array.id)
141 length = '__a%s->values.size()' % array.id
142 index = '__j' + array.id
143 print ' for(size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
144 try:
145 self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.id, index))
146 finally:
147 print ' }'
148 print ' }'
149
150 def visit_pointer(self, pointer, lvalue, rvalue):
151 print ' const Trace::Array *__a%s = dynamic_cast<const Trace::Array *>(&%s);' % (pointer.id, rvalue)
152 print ' if (__a%s) {' % (pointer.id)
153 try:
154 self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.id,))
155 finally:
156 print ' }'
157
José Fonsecae0e61402010-11-25 15:03:23 +0000158 def visit_handle(self, handle, lvalue, rvalue):
José Fonsecaa10af892011-04-11 09:10:55 +0100159 print ' %s __orig_result;' % handle.type
160 OpaqueValueExtractor().visit(handle.type, '__orig_result', rvalue);
José Fonsecad922e1d2010-11-25 17:14:02 +0000161 if handle.range is None:
José Fonsecaa10af892011-04-11 09:10:55 +0100162 rvalue = "__orig_result"
José Fonseca8a844ae2010-12-06 18:50:52 +0000163 entry = handle_entry(handle, rvalue)
164 print " %s = %s;" % (entry, lvalue)
José Fonseca32871ed2011-04-10 13:40:52 +0100165 print ' if (retrace::verbosity >= 2)'
José Fonseca8a844ae2010-12-06 18:50:52 +0000166 print ' std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
José Fonsecad922e1d2010-11-25 17:14:02 +0000167 else:
168 i = '__h' + handle.id
José Fonseca8a844ae2010-12-06 18:50:52 +0000169 lvalue = "%s + %s" % (lvalue, i)
José Fonsecaa10af892011-04-11 09:10:55 +0100170 rvalue = "__orig_result + %s" % (i,)
José Fonseca8a844ae2010-12-06 18:50:52 +0000171 entry = handle_entry(handle, rvalue)
José Fonsecad922e1d2010-11-25 17:14:02 +0000172 print ' for({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
José Fonseca8a844ae2010-12-06 18:50:52 +0000173 print ' {entry} = {lvalue};'.format(**locals())
José Fonseca32871ed2011-04-10 13:40:52 +0100174 print ' if (retrace::verbosity >= 2)'
José Fonseca8a844ae2010-12-06 18:50:52 +0000175 print ' std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
José Fonsecad922e1d2010-11-25 17:14:02 +0000176 print ' }'
José Fonsecae0e61402010-11-25 15:03:23 +0000177
178 def visit_blob(self, blob, lvalue, rvalue):
179 pass
180
181 def visit_string(self, string, lvalue, rvalue):
182 pass
183
184
José Fonsecae0e61402010-11-25 15:03:23 +0000185class Retracer:
186
187 def retrace_function(self, function):
188 print 'static void retrace_%s(Trace::Call &call) {' % function.name
José Fonseca62212972011-03-23 13:22:55 +0000189 self.retrace_function_body(function)
190 print '}'
191 print
192
193 def retrace_function_body(self, function):
José Fonsecae0e61402010-11-25 15:03:23 +0000194 success = True
195 for arg in function.args:
196 arg_type = ConstRemover().visit(arg.type)
197 #print ' // %s -> %s' % (arg.type, arg_type)
198 print ' %s %s;' % (arg_type, arg.name)
199 rvalue = 'call.arg(%u)' % (arg.index,)
200 lvalue = arg.name
201 try:
José Fonsecadacd8dd2010-11-25 17:50:26 +0000202 self.extract_arg(function, arg, arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000203 except NotImplementedError:
204 success = False
205 print ' %s = 0; // FIXME' % arg.name
206 if not success:
José Fonsecafa15d332010-11-25 20:22:39 +0000207 self.fail_function(function)
208 self.call_function(function)
José Fonsecae0e61402010-11-25 15:03:23 +0000209 for arg in function.args:
210 if arg.output:
211 arg_type = ConstRemover().visit(arg.type)
212 rvalue = 'call.arg(%u)' % (arg.index,)
213 lvalue = arg.name
214 try:
215 ValueWrapper().visit(arg_type, lvalue, rvalue)
216 except NotImplementedError:
217 print ' // FIXME: %s' % arg.name
218 if function.type is not stdapi.Void:
219 rvalue = '*call.ret'
220 lvalue = '__result'
221 try:
222 ValueWrapper().visit(function.type, lvalue, rvalue)
223 except NotImplementedError:
224 print ' // FIXME: result'
José Fonsecae0e61402010-11-25 15:03:23 +0000225
José Fonsecafa15d332010-11-25 20:22:39 +0000226 def fail_function(self, function):
José Fonseca32871ed2011-04-10 13:40:52 +0100227 print ' if (retrace::verbosity >= 0)'
José Fonseca5e687162011-02-09 15:11:12 +0000228 print ' std::cerr << "warning: unsupported call %s\\n";' % function.name
José Fonsecafa15d332010-11-25 20:22:39 +0000229 print ' return;'
230
José Fonsecadacd8dd2010-11-25 17:50:26 +0000231 def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
232 ValueExtractor().visit(arg_type, lvalue, rvalue)
José Fonsecae0e61402010-11-25 15:03:23 +0000233
José Fonsecafa15d332010-11-25 20:22:39 +0000234 def call_function(self, function):
235 arg_names = ", ".join([arg.name for arg in function.args])
236 if function.type is not stdapi.Void:
237 print ' %s __result;' % (function.type)
238 print ' __result = %s(%s);' % (function.name, arg_names)
239 else:
240 print ' %s(%s);' % (function.name, arg_names)
241
José Fonseca4441baf2010-11-25 19:55:27 +0000242 def filter_function(self, function):
243 return True
244
José Fonsecae0e61402010-11-25 15:03:23 +0000245 def retrace_functions(self, functions):
José Fonseca4441baf2010-11-25 19:55:27 +0000246 functions = filter(self.filter_function, functions)
247
José Fonsecae0e61402010-11-25 15:03:23 +0000248 for function in functions:
249 if function.sideeffects:
250 self.retrace_function(function)
251
José Fonseca32871ed2011-04-10 13:40:52 +0100252 print 'bool retrace::retrace_call(Trace::Call &call) {'
José Fonseca522b7442010-11-27 15:30:40 +0000253 print ' const char *name = call.name().c_str();'
José Fonsecae0e61402010-11-25 15:03:23 +0000254 print
José Fonseca32871ed2011-04-10 13:40:52 +0100255 print ' if (retrace::verbosity >= 1) {'
José Fonsecae0e61402010-11-25 15:03:23 +0000256 print ' std::cout << call;'
257 print ' std::cout.flush();'
258 print ' };'
259 print
José Fonseca522b7442010-11-27 15:30:40 +0000260
261 func_dict = dict([(function.name, function) for function in functions])
262
263 def handle_case(function_name):
264 function = func_dict[function_name]
José Fonsecae0e61402010-11-25 15:03:23 +0000265 if function.sideeffects:
José Fonsecae0e61402010-11-25 15:03:23 +0000266 print ' retrace_%s(call);' % function.name
José Fonseca522b7442010-11-27 15:30:40 +0000267 print ' return true;'
268
269 string_switch('name', func_dict.keys(), handle_case)
270
José Fonseca32871ed2011-04-10 13:40:52 +0100271 print ' if (retrace::verbosity >= 0)'
José Fonseca5e687162011-02-09 15:11:12 +0000272 print ' std::cerr << "warning: unknown call " << call.name() << "\\n";'
José Fonsecae0e61402010-11-25 15:03:23 +0000273 print ' return false;'
274 print '}'
275 print
276
277
278 def retrace_api(self, api):
279
280 print '#include "trace_parser.hpp"'
José Fonseca91343f52011-04-01 08:37:06 +0100281 print '#include "retrace.hpp"'
José Fonsecae0e61402010-11-25 15:03:23 +0000282 print
283
284 types = api.all_types()
285 handles = [type for type in types if isinstance(type, stdapi.Handle)]
José Fonsecad922e1d2010-11-25 17:14:02 +0000286 handle_names = set()
José Fonsecae0e61402010-11-25 15:03:23 +0000287 for handle in handles:
José Fonsecad922e1d2010-11-25 17:14:02 +0000288 if handle.name not in handle_names:
José Fonseca8a844ae2010-12-06 18:50:52 +0000289 if handle.key is None:
José Fonseca91343f52011-04-01 08:37:06 +0100290 print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
José Fonseca8a844ae2010-12-06 18:50:52 +0000291 else:
292 key_name, key_type = handle.key
José Fonseca91343f52011-04-01 08:37:06 +0100293 print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
José Fonsecad922e1d2010-11-25 17:14:02 +0000294 handle_names.add(handle.name)
José Fonsecae0e61402010-11-25 15:03:23 +0000295 print
296
José Fonsecae0e61402010-11-25 15:03:23 +0000297 self.retrace_functions(api.functions)
298