]> git.cworth.org Git - apitrace/blob - trace.py
More compact struct representation.
[apitrace] / trace.py
1 ##########################################################################
2 #
3 # Copyright 2008-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 """C basic types"""
27
28
29 import stdapi
30
31
32 all_types = {}
33
34
35 class DumpDeclarator(stdapi.OnceVisitor):
36     '''Declare helper functions to dump complex types.'''
37
38     def visit_void(self, literal):
39         pass
40
41     def visit_literal(self, literal):
42         pass
43
44     def visit_string(self, string):
45         pass
46
47     def visit_const(self, const):
48         self.visit(const.type)
49
50     def visit_struct(self, struct):
51         for type, name in struct.members:
52             self.visit(type)
53         print 'static void __traceStruct%s(const %s &value) {' % (struct.id, struct.expr)
54         print '    static const char * members[%u] = {' % (len(struct.members),)
55         for type, name,  in struct.members:
56             print '        "%s",' % (name,)
57         print '    };'
58         print '    static const Trace::StructSig sig = {'
59         print '       %u, "%s", %u, members' % (int(struct.id), struct.name, len(struct.members))
60         print '    };'
61         print '    Trace::BeginStruct(&sig);'
62         for type, name in struct.members:
63             dump_instance(type, 'value.%s' % (name,))
64         print '    Trace::EndStruct();'
65         print '}'
66         print
67
68     def visit_array(self, array):
69         self.visit(array.type)
70
71     def visit_blob(self, array):
72         pass
73
74     def visit_enum(self, enum):
75         print 'static void __traceEnum%s(const %s value) {' % (enum.id, enum.expr)
76         n = len(enum.values)
77         for i in range(n):
78             value = enum.values[i]
79             print '    static const Trace::EnumSig sig%u = {%u, "%s", %s};' % (i, enum.vid + i, value, value)
80         print '    const Trace::EnumSig *sig;'
81         print '    switch(value) {'
82         for i in range(n):
83             value = enum.values[i]
84             print '    case %s:' % value
85             print '        sig = &sig%u;' % i
86             print '        break;'
87         print '    default:'
88         print '        Trace::LiteralSInt(value);'
89         print '        return;'
90         print '    }'
91         print '        Trace::LiteralEnum(sig);'
92         print '}'
93         print
94
95     def visit_bitmask(self, bitmask):
96         print 'static const Trace::BitmaskVal __bitmask%s_vals[] = {' % (bitmask.id)
97         for value in bitmask.values:
98             print '   {"%s", %s},' % (value, value)
99         print '};'
100         print
101         print 'static const Trace::BitmaskSig __bitmask%s_sig = {' % (bitmask.id)
102         print '   %u, %u, __bitmask%s_vals' % (int(bitmask.id), len(bitmask.values), bitmask.id)
103         print '};'
104         print
105
106     def visit_pointer(self, pointer):
107         self.visit(pointer.type)
108
109     def visit_handle(self, handle):
110         self.visit(handle.type)
111
112     def visit_alias(self, alias):
113         self.visit(alias.type)
114
115     def visit_opaque(self, opaque):
116         pass
117
118     def visit_interface(self, interface):
119         pass
120
121
122 class DumpImplementer(stdapi.Visitor):
123     '''Dump an instance.'''
124
125     def visit_literal(self, literal, instance):
126         print '    Trace::Literal%s(%s);' % (literal.format, instance)
127
128     def visit_string(self, string, instance):
129         if string.length is not None:
130             print '    Trace::LiteralString((const char *)%s, %s);' % (instance, string.length)
131         else:
132             print '    Trace::LiteralString((const char *)%s);' % instance
133
134     def visit_const(self, const, instance):
135         self.visit(const.type, instance)
136
137     def visit_struct(self, struct, instance):
138         print '    __traceStruct%s(%s);' % (struct.id, instance)
139
140     def visit_array(self, array, instance):
141         print '    if(%s) {' % instance
142         index = '__i' + array.type.id
143         print '        Trace::BeginArray(%s);' % (array.length,)
144         print '        for (int %s = 0; %s < %s; ++%s) {' % (index, index, array.length, index)
145         print '            Trace::BeginElement();'
146         self.visit(array.type, '(%s)[%s]' % (instance, index))
147         print '            Trace::EndElement();'
148         print '        }'
149         print '        Trace::EndArray();'
150         print '    }'
151         print '    else'
152         print '        Trace::LiteralNull();'
153
154     def visit_blob(self, blob, instance):
155         print '    Trace::LiteralBlob(%s, %s);' % (instance, blob.size)
156
157     def visit_enum(self, enum, instance):
158         print '    __traceEnum%s(%s);' % (enum.id, instance)
159
160     def visit_bitmask(self, bitmask, instance):
161         print '    Trace::LiteralBitmask(__bitmask%s_sig, %s);' % (bitmask.id, instance)
162
163     def visit_pointer(self, pointer, instance):
164         print '    if(%s) {' % instance
165         print '        Trace::BeginArray(1);'
166         print '        Trace::BeginElement();'
167         dump_instance(pointer.type, "*" + instance)
168         print '        Trace::EndElement();'
169         print '        Trace::EndArray();'
170         print '    }'
171         print '    else'
172         print '        Trace::LiteralNull();'
173
174     def visit_handle(self, handle, instance):
175         self.visit(handle.type, instance)
176
177     def visit_alias(self, alias, instance):
178         self.visit(alias.type, instance)
179
180     def visit_opaque(self, opaque, instance):
181         print '    Trace::LiteralOpaque((const void *)%s);' % instance
182
183     def visit_interface(self, interface, instance):
184         print '    Trace::LiteralOpaque((const void *)%s);' % instance
185
186
187 dump_instance = DumpImplementer().visit
188
189
190
191 class Wrapper(stdapi.Visitor):
192     '''Wrap an instance.'''
193
194     def visit_void(self, type, instance):
195         raise NotImplementedError
196
197     def visit_literal(self, type, instance):
198         pass
199
200     def visit_string(self, type, instance):
201         pass
202
203     def visit_const(self, type, instance):
204         pass
205
206     def visit_struct(self, struct, instance):
207         for type, name in struct.members:
208             self.visit(type, "(%s).%s" % (instance, name))
209
210     def visit_array(self, array, instance):
211         # XXX: actually it is possible to return an array of pointers
212         pass
213
214     def visit_blob(self, blob, instance):
215         pass
216
217     def visit_enum(self, enum, instance):
218         pass
219
220     def visit_bitmask(self, bitmask, instance):
221         pass
222
223     def visit_pointer(self, pointer, instance):
224         self.visit(pointer.type, "*" + instance)
225
226     def visit_handle(self, handle, instance):
227         self.visit(handle.type, instance)
228
229     def visit_alias(self, alias, instance):
230         self.visit(alias.type, instance)
231
232     def visit_opaque(self, opaque, instance):
233         pass
234     
235     def visit_interface(self, interface, instance):
236         print "    if(%s)" % instance
237         print "        %s = new %s(%s);" % (instance, interface.type.wrap_name(), instance)
238
239
240 class Unwrapper(Wrapper):
241
242     def visit_interface(self, interface, instance):
243         print "    if(%s)" % instance
244         print "        %s = static_cast<%s *>(%s)->m_pInstance;" % (instance, interface.type.wrap_name(), instance)
245
246 wrap_instance = Wrapper().visit
247 unwrap_instance = Unwrapper().visit
248
249
250 class Tracer:
251
252     def trace_api(self, api):
253         self.header(api)
254
255         # Includes
256         for header in api.headers:
257             print header
258         print
259
260         # Type dumpers
261         types = api.all_types()
262         visitor = DumpDeclarator()
263         map(visitor.visit, types)
264         print
265
266         # Interfaces wrapers
267         map(self.interface_wrap_name, api.interfaces)
268         map(self.interface_pre_decl, api.interfaces)
269         map(self.interface_decl, api.interfaces)
270         map(self.interface_wrap_impl, api.interfaces)
271         print
272
273         # Function wrappers
274         map(self.trace_function_decl, api.functions)
275         map(self.trace_function_impl, api.functions)
276         print
277
278         self.footer(api)
279
280     def header(self, api):
281         pass
282
283     def footer(self, api):
284         pass
285
286     def function_pointer_type(self, function):
287         return 'P' + function.name
288
289     def function_pointer_value(self, function):
290         return 'p' + function.name
291
292     def trace_function_decl(self, function):
293         ptype = self.function_pointer_type(function)
294         pvalue = self.function_pointer_value(function)
295         print 'typedef ' + function.prototype('* %s' % ptype) + ';'
296         print 'static %s %s = NULL;' % (ptype, pvalue)
297         print
298         print 'static const char * __%s_args[] = {' % (function.name)
299         for arg in function.args:
300             print '   "%s",' % (arg.name,)
301         print '};'
302         print
303         print 'static const Trace::FunctionSig __%s_sig = {' % (function.name)
304         print '   %u, "%s", %u, __%s_args' % (int(function.id), function.name, len(function.args), function.name)
305         print '};'
306         print
307
308
309     def trace_function_fail(self, function):
310         if function.fail is not None:
311             if function.type is stdapi.Void:
312                 assert function.fail == ''
313                 print '            return;' 
314             else:
315                 assert function.fail != ''
316                 print '            return %s;' % function.fail
317         else:
318             print '            Trace::Abort();'
319
320     def get_function_address(self, function):
321         raise NotImplementedError
322
323     def _get_true_pointer(self, function):
324         ptype = self.function_pointer_type(function)
325         pvalue = self.function_pointer_value(function)
326         print '    if(!%s) {' % (pvalue,)
327         print '        %s = (%s)%s;' % (pvalue, ptype, self.get_function_address(function))
328         print '        if(!%s)' % (pvalue,)
329         self.trace_function_fail(function)
330         print '    }'
331
332     def trace_function_impl(self, function):
333         pvalue = self.function_pointer_value(function)
334         print function.prototype() + ' {'
335         if function.type is stdapi.Void:
336             result = ''
337         else:
338             print '    %s __result;' % function.type
339             result = '__result = '
340         self._get_true_pointer(function)
341         print '    unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name)
342         for arg in function.args:
343             if not arg.output:
344                 self.unwrap_arg(function, arg)
345                 self.dump_arg(function, arg)
346         print '    Trace::EndEnter();'
347         print '    %s%s(%s);' % (result, pvalue, ', '.join([str(arg.name) for arg in function.args]))
348         print '    Trace::BeginLeave(__call);'
349         for arg in function.args:
350             if arg.output:
351                 self.dump_arg(function, arg)
352                 self.wrap_arg(function, arg)
353         if function.type is not stdapi.Void:
354             self.dump_ret(function, "__result")
355         print '    Trace::EndLeave();'
356         if function.type is not stdapi.Void:
357             self.wrap_ret(function, "__result")
358             print '    return __result;'
359         print '}'
360         print
361
362     def dump_arg(self, function, arg):
363         print '    Trace::BeginArg(%u);' % (arg.index,)
364         dump_instance(arg.type, arg.name)
365         print '    Trace::EndArg();'
366
367     def wrap_arg(self, function, arg):
368         wrap_instance(arg.type, arg.name)
369
370     def unwrap_arg(self, function, arg):
371         unwrap_instance(arg.type, arg.name)
372
373     def dump_ret(self, function, instance):
374         print '    Trace::BeginReturn();'
375         dump_instance(function.type, instance)
376         print '    Trace::EndReturn();'
377
378     def wrap_ret(self, function, instance):
379         wrap_instance(function.type, instance)
380
381     def unwrap_ret(self, function, instance):
382         unwrap_instance(function.type, instance)
383
384     def interface_wrap_name(self, interface):
385         return "Wrap" + interface.expr
386
387     def interface_pre_decl(self, interface):
388         print "class %s;" % interface.wrap_name()
389
390     def interface_decl(self, interface):
391         print "class %s : public %s " % (interface.wrap_name(), interface.name)
392         print "{"
393         print "public:"
394         print "    %s(%s * pInstance);" % (interface.wrap_name(), interface.name)
395         print "    virtual ~%s();" % interface.wrap_name()
396         print
397         for method in interface.itermethods():
398             print "    " + method.prototype() + ";"
399         print
400         #print "private:"
401         print "    %s * m_pInstance;" % (interface.name,)
402         print "};"
403         print
404
405     def interface_wrap_impl(self, interface):
406         print '%s::%s(%s * pInstance) {' % (interface.wrap_name(), interface.wrap_name(), interface.name)
407         print '    m_pInstance = pInstance;'
408         print '}'
409         print
410         print '%s::~%s() {' % (interface.wrap_name(), interface.wrap_name())
411         print '}'
412         print
413         for method in interface.itermethods():
414             self.trace_method(interface, method)
415         print
416
417     def trace_method(self, interface, method):
418         print method.prototype(interface.wrap_name() + '::' + method.name) + ' {'
419         if method.type is Void:
420             result = ''
421         else:
422             print '    %s __result;' % method.type
423             result = '__result = '
424         print '    Trace::BeginCall("%s");' % (interface.name + '::' + method.name)
425         print '    Trace::BeginArg(0);'
426         print '    Trace::LiteralOpaque((const void *)m_pInstance);'
427         print '    Trace::EndArg();'
428         for arg in method.args:
429             if not arg.output:
430                 self.unwrap_arg(method, arg)
431                 self.dump_arg(method, arg)
432         print '    %sm_pInstance->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args]))
433         for arg in method.args:
434             if arg.output:
435                 self.dump_arg(method, arg)
436                 self.wrap_arg(method, arg)
437         if method.type is not Void:
438             print '    Trace::BeginReturn("%s");' % method.type
439             dump_instance(method.type, "__result")
440             print '    Trace::EndReturn();'
441             wrap_instance(method.type, '__result')
442         print '    Trace::EndCall();'
443         if method.name == 'QueryInterface':
444             print '    if (*ppvObj == m_pInstance)'
445             print '        *ppvObj = this;'
446         if method.name == 'Release':
447             assert method.type is not Void
448             print '    if (!__result)'
449             print '        delete this;'
450         if method.type is not Void:
451             print '    return __result;'
452         print '}'
453         print
454
455