1#!/usr/bin/env python2
2##########################################################################
3#
4# Copyright 2008 VMware, Inc.
5# All Rights Reserved.
6#
7# Permission is hereby granted, free of charge, to any person obtaining a
8# copy of this software and associated documentation files (the
9# "Software"), to deal in the Software without restriction, including
10# without limitation the rights to use, copy, modify, merge, publish,
11# distribute, sub license, and/or sell copies of the Software, and to
12# permit persons to whom the Software is furnished to do so, subject to
13# the following conditions:
14#
15# The above copyright notice and this permission notice (including the
16# next paragraph) shall be included in all copies or substantial portions
17# of the Software.
18#
19# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26#
27##########################################################################
28
29
30'''Trace data model.'''
31
32
33import sys
34import string
35import binascii
36
37try:
38    from cStringIO import StringIO
39except ImportError:
40    from StringIO import StringIO
41
42import format
43
44
45class Node:
46
47    def visit(self, visitor):
48        raise NotImplementedError
49
50    def __str__(self):
51        stream = StringIO()
52        formatter = format.DefaultFormatter(stream)
53        pretty_printer = PrettyPrinter(formatter)
54        self.visit(pretty_printer)
55        return stream.getvalue()
56
57
58class Literal(Node):
59
60    def __init__(self, value):
61        self.value = value
62
63    def visit(self, visitor):
64        visitor.visit_literal(self)
65
66
67class Blob(Node):
68
69    def __init__(self, value):
70        self._rawValue = None
71        self._hexValue = value
72
73    def getValue(self):
74        if self._rawValue is None:
75            self._rawValue = binascii.a2b_hex(self._hexValue)
76            self._hexValue = None
77        return self._rawValue
78
79    def visit(self, visitor):
80        visitor.visit_blob(self)
81
82
83class NamedConstant(Node):
84
85    def __init__(self, name):
86        self.name = name
87
88    def visit(self, visitor):
89        visitor.visit_named_constant(self)
90
91
92class Array(Node):
93
94    def __init__(self, elements):
95        self.elements = elements
96
97    def visit(self, visitor):
98        visitor.visit_array(self)
99
100
101class Struct(Node):
102
103    def __init__(self, name, members):
104        self.name = name
105        self.members = members
106
107    def visit(self, visitor):
108        visitor.visit_struct(self)
109
110
111class Pointer(Node):
112
113    def __init__(self, address):
114        self.address = address
115
116    def visit(self, visitor):
117        visitor.visit_pointer(self)
118
119
120class Call:
121
122    def __init__(self, no, klass, method, args, ret, time):
123        self.no = no
124        self.klass = klass
125        self.method = method
126        self.args = args
127        self.ret = ret
128        self.time = time
129
130    def visit(self, visitor):
131        visitor.visit_call(self)
132
133
134class Trace:
135
136    def __init__(self, calls):
137        self.calls = calls
138
139    def visit(self, visitor):
140        visitor.visit_trace(self)
141
142
143class Visitor:
144
145    def visit_literal(self, node):
146        raise NotImplementedError
147
148    def visit_blob(self, node):
149        raise NotImplementedError
150
151    def visit_named_constant(self, node):
152        raise NotImplementedError
153
154    def visit_array(self, node):
155        raise NotImplementedError
156
157    def visit_struct(self, node):
158        raise NotImplementedError
159
160    def visit_pointer(self, node):
161        raise NotImplementedError
162
163    def visit_call(self, node):
164        raise NotImplementedError
165
166    def visit_trace(self, node):
167        raise NotImplementedError
168
169
170class PrettyPrinter:
171
172    def __init__(self, formatter):
173        self.formatter = formatter
174
175    def visit_literal(self, node):
176        if node.value is None:
177            self.formatter.literal('NULL')
178            return
179
180        if isinstance(node.value, basestring):
181            self.formatter.literal('"' + node.value + '"')
182            return
183
184        self.formatter.literal(repr(node.value))
185
186    def visit_blob(self, node):
187        self.formatter.address('blob()')
188
189    def visit_named_constant(self, node):
190        self.formatter.literal(node.name)
191
192    def visit_array(self, node):
193        self.formatter.text('{')
194        sep = ''
195        for value in node.elements:
196            self.formatter.text(sep)
197            value.visit(self)
198            sep = ', '
199        self.formatter.text('}')
200
201    def visit_struct(self, node):
202        self.formatter.text('{')
203        sep = ''
204        for name, value in node.members:
205            self.formatter.text(sep)
206            self.formatter.variable(name)
207            self.formatter.text(' = ')
208            value.visit(self)
209            sep = ', '
210        self.formatter.text('}')
211
212    def visit_pointer(self, node):
213        self.formatter.address(node.address)
214
215    def visit_call(self, node):
216        self.formatter.text('%s ' % node.no)
217        if node.klass is not None:
218            self.formatter.function(node.klass + '::' + node.method)
219        else:
220            self.formatter.function(node.method)
221        self.formatter.text('(')
222        sep = ''
223        for name, value in node.args:
224            self.formatter.text(sep)
225            self.formatter.variable(name)
226            self.formatter.text(' = ')
227            value.visit(self)
228            sep = ', '
229        self.formatter.text(')')
230        if node.ret is not None:
231            self.formatter.text(' = ')
232            node.ret.visit(self)
233        if node.time is not None:
234            self.formatter.text(' // time ')
235            node.time.visit(self)
236
237    def visit_trace(self, node):
238        for call in node.calls:
239            call.visit(self)
240            self.formatter.newline()
241
242