1#!/usr/local/bin/python3.8
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
36from io import StringIO
37import format
38
39
40class Node:
41
42    def visit(self, visitor):
43        raise NotImplementedError
44
45    def __str__(self):
46        stream = StringIO()
47        formatter = format.Formatter(stream)
48        pretty_printer = PrettyPrinter(formatter, {})
49        self.visit(pretty_printer)
50        return stream.getvalue()
51
52
53class Literal(Node):
54
55    def __init__(self, value):
56        self.value = value
57
58    def visit(self, visitor):
59        visitor.visit_literal(self)
60
61
62class Blob(Node):
63
64    def __init__(self, value):
65        self._rawValue = None
66        self._hexValue = value
67
68    def getValue(self):
69        if self._rawValue is None:
70            self._rawValue = binascii.a2b_hex(self._hexValue)
71            self._hexValue = None
72        return self._rawValue
73
74    def visit(self, visitor):
75        visitor.visit_blob(self)
76
77
78class NamedConstant(Node):
79
80    def __init__(self, name):
81        self.name = name
82
83    def visit(self, visitor):
84        visitor.visit_named_constant(self)
85
86
87class Array(Node):
88
89    def __init__(self, elements):
90        self.elements = elements
91
92    def visit(self, visitor):
93        visitor.visit_array(self)
94
95
96class Struct(Node):
97
98    def __init__(self, name, members):
99        self.name = name
100        self.members = members
101
102    def visit(self, visitor):
103        visitor.visit_struct(self)
104
105
106class Pointer(Node):
107
108    ptr_list = {}
109    ptr_type_list = {}
110    ptr_types_list = {}
111    ptr_ignore_list = ["ret", "elem"]
112
113    def __init__(self, address, pname):
114        self.address = address
115
116        # Check if address exists in list and if it is a return value address
117        t1 = address in self.ptr_list
118        if t1:
119            rname = self.ptr_type_list[address]
120            t2 = rname in self.ptr_ignore_list and pname not in self.ptr_ignore_list
121        else:
122            rname = pname
123            t2 = False
124
125        # If address does NOT exist (add it), OR IS a ret value (update with new type)
126        if not t1 or t2:
127            # If previously set to ret value, remove one from count
128            if t1 and t2:
129                self.adjust_ptr_type_count(rname, -1)
130
131            # Add / update
132            self.adjust_ptr_type_count(pname, 1)
133            tmp = "{}_{}".format(pname, self.ptr_types_list[pname])
134            self.ptr_list[address] = tmp
135            self.ptr_type_list[address] = pname
136
137    def adjust_ptr_type_count(self, pname, delta):
138        if pname not in self.ptr_types_list:
139            self.ptr_types_list[pname] = 0
140
141        self.ptr_types_list[pname] += delta
142
143    def visit(self, visitor):
144        visitor.visit_pointer(self)
145
146
147class Call:
148
149    def __init__(self, no, klass, method, args, ret, time):
150        self.no = no
151        self.klass = klass
152        self.method = method
153        self.args = args
154        self.ret = ret
155        self.time = time
156
157    def visit(self, visitor):
158        visitor.visit_call(self)
159
160
161class Trace:
162
163    def __init__(self, calls):
164        self.calls = calls
165
166    def visit(self, visitor):
167        visitor.visit_trace(self)
168
169
170class Visitor:
171
172    def visit_literal(self, node):
173        raise NotImplementedError
174
175    def visit_blob(self, node):
176        raise NotImplementedError
177
178    def visit_named_constant(self, node):
179        raise NotImplementedError
180
181    def visit_array(self, node):
182        raise NotImplementedError
183
184    def visit_struct(self, node):
185        raise NotImplementedError
186
187    def visit_pointer(self, node):
188        raise NotImplementedError
189
190    def visit_call(self, node):
191        raise NotImplementedError
192
193    def visit_trace(self, node):
194        raise NotImplementedError
195
196
197class PrettyPrinter:
198
199    def __init__(self, formatter, options):
200        self.formatter = formatter
201        self.options = options
202
203    def visit_literal(self, node):
204        if node.value is None:
205            self.formatter.literal('NULL')
206            return
207
208        if isinstance(node.value, str):
209            self.formatter.literal('"' + node.value + '"')
210            return
211
212        self.formatter.literal(repr(node.value))
213
214    def visit_blob(self, node):
215        self.formatter.address('blob()')
216
217    def visit_named_constant(self, node):
218        self.formatter.literal(node.name)
219
220    def visit_array(self, node):
221        self.formatter.text('{')
222        sep = ''
223        for value in node.elements:
224            self.formatter.text(sep)
225            value.visit(self)
226            sep = ', '
227        self.formatter.text('}')
228
229    def visit_struct(self, node):
230        self.formatter.text('{')
231        sep = ''
232        for name, value in node.members:
233            self.formatter.text(sep)
234            self.formatter.variable(name)
235            self.formatter.text(' = ')
236            value.visit(self)
237            sep = ', '
238        self.formatter.text('}')
239
240    def visit_pointer(self, node):
241        if "named_ptrs" in self.options and self.options.named_ptrs:
242            self.formatter.address(node.ptr_list[node.address])
243        else:
244            self.formatter.address(node.address)
245
246    def visit_call(self, node):
247        if not self.options.suppress_variants:
248            self.formatter.text('%s ' % node.no)
249
250        if node.klass is not None:
251            self.formatter.function(node.klass + '::' + node.method)
252        else:
253            self.formatter.function(node.method)
254
255        if not self.options.method_only:
256            self.formatter.text('(')
257            sep = ''
258            for name, value in node.args:
259                self.formatter.text(sep)
260                self.formatter.variable(name)
261                self.formatter.text(' = ')
262                value.visit(self)
263                sep = ', '
264            self.formatter.text(')')
265            if node.ret is not None:
266                self.formatter.text(' = ')
267                node.ret.visit(self)
268
269        if not self.options.suppress_variants and node.time is not None:
270            self.formatter.text(' // time ')
271            node.time.visit(self)
272
273    def visit_trace(self, node):
274        for call in node.calls:
275            call.visit(self)
276            self.formatter.newline()
277
278