1bf215546Sopenharmony_ci#!/usr/bin/env python3
2bf215546Sopenharmony_ci##########################################################################
3bf215546Sopenharmony_ci#
4bf215546Sopenharmony_ci# Copyright 2008 VMware, Inc.
5bf215546Sopenharmony_ci# All Rights Reserved.
6bf215546Sopenharmony_ci#
7bf215546Sopenharmony_ci# Permission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_ci# copy of this software and associated documentation files (the
9bf215546Sopenharmony_ci# "Software"), to deal in the Software without restriction, including
10bf215546Sopenharmony_ci# without limitation the rights to use, copy, modify, merge, publish,
11bf215546Sopenharmony_ci# distribute, sub license, and/or sell copies of the Software, and to
12bf215546Sopenharmony_ci# permit persons to whom the Software is furnished to do so, subject to
13bf215546Sopenharmony_ci# the following conditions:
14bf215546Sopenharmony_ci#
15bf215546Sopenharmony_ci# The above copyright notice and this permission notice (including the
16bf215546Sopenharmony_ci# next paragraph) shall be included in all copies or substantial portions
17bf215546Sopenharmony_ci# of the Software.
18bf215546Sopenharmony_ci#
19bf215546Sopenharmony_ci# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20bf215546Sopenharmony_ci# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21bf215546Sopenharmony_ci# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22bf215546Sopenharmony_ci# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23bf215546Sopenharmony_ci# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24bf215546Sopenharmony_ci# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25bf215546Sopenharmony_ci# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26bf215546Sopenharmony_ci#
27bf215546Sopenharmony_ci##########################################################################
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci'''Trace data model.'''
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ciimport sys
34bf215546Sopenharmony_ciimport string
35bf215546Sopenharmony_ciimport binascii
36bf215546Sopenharmony_cifrom io import StringIO
37bf215546Sopenharmony_ciimport format
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ciclass ModelOptions:
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci    def __init__(self, args=None):
43bf215546Sopenharmony_ci        # Initialize the options we need to exist,
44bf215546Sopenharmony_ci        # with some reasonable defaults
45bf215546Sopenharmony_ci        self.plain = False
46bf215546Sopenharmony_ci        self.suppress_variants = False
47bf215546Sopenharmony_ci        self.named_ptrs = False
48bf215546Sopenharmony_ci        self.method_only = False
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci        # If args is specified, we assume it is the result object
51bf215546Sopenharmony_ci        # from ArgumentParser.parse_args(). Copy the attribute values
52bf215546Sopenharmony_ci        # we have from it, if they exist.
53bf215546Sopenharmony_ci        if args is not None:
54bf215546Sopenharmony_ci            for var in self.__dict__:
55bf215546Sopenharmony_ci                if var in args.__dict__:
56bf215546Sopenharmony_ci                    self.__dict__[var] = args.__dict__[var]
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ciclass TraceStateData:
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci    def __init__(self):
62bf215546Sopenharmony_ci        self.ptr_list = {}
63bf215546Sopenharmony_ci        self.ptr_type_list = {}
64bf215546Sopenharmony_ci        self.ptr_types_list = {}
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ciclass Node:
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci    def visit(self, visitor):
70bf215546Sopenharmony_ci        raise NotImplementedError
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci    def __str__(self):
73bf215546Sopenharmony_ci        stream = StringIO()
74bf215546Sopenharmony_ci        formatter = format.Formatter(stream)
75bf215546Sopenharmony_ci        pretty_printer = PrettyPrinter(formatter, {})
76bf215546Sopenharmony_ci        self.visit(pretty_printer)
77bf215546Sopenharmony_ci        return stream.getvalue()
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci    def __hash__(self):
80bf215546Sopenharmony_ci        raise NotImplementedError
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ciclass Literal(Node):
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci    def __init__(self, value):
86bf215546Sopenharmony_ci        self.value = value
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci    def visit(self, visitor):
89bf215546Sopenharmony_ci        visitor.visit_literal(self)
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci    def __hash__(self):
92bf215546Sopenharmony_ci        return hash(self.value)
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ciclass Blob(Node):
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci    def __init__(self, value):
98bf215546Sopenharmony_ci        self.value = binascii.a2b_hex(value)
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci    def getValue(self):
101bf215546Sopenharmony_ci        return self.value
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci    def visit(self, visitor):
104bf215546Sopenharmony_ci        visitor.visit_blob(self)
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci    def __hash__(self):
107bf215546Sopenharmony_ci        return hash(self.value)
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ciclass NamedConstant(Node):
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci    def __init__(self, name):
113bf215546Sopenharmony_ci        self.name = name
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci    def visit(self, visitor):
116bf215546Sopenharmony_ci        visitor.visit_named_constant(self)
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci    def __hash__(self):
119bf215546Sopenharmony_ci        return hash(self.name)
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ciclass Array(Node):
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci    def __init__(self, elements):
125bf215546Sopenharmony_ci        self.elements = elements
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci    def visit(self, visitor):
128bf215546Sopenharmony_ci        visitor.visit_array(self)
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci    def __hash__(self):
131bf215546Sopenharmony_ci        tmp = 0
132bf215546Sopenharmony_ci        for mobj in self.elements:
133bf215546Sopenharmony_ci            tmp = tmp ^ hash(mobj)
134bf215546Sopenharmony_ci        return tmp
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ciclass Struct(Node):
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci    def __init__(self, name, members):
140bf215546Sopenharmony_ci        self.name = name
141bf215546Sopenharmony_ci        self.members = members
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci    def visit(self, visitor):
144bf215546Sopenharmony_ci        visitor.visit_struct(self)
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci    def __hash__(self):
147bf215546Sopenharmony_ci        tmp = hash(self.name)
148bf215546Sopenharmony_ci        for mname, mobj in self.members:
149bf215546Sopenharmony_ci            tmp = tmp ^ hash(mname) ^ hash(mobj)
150bf215546Sopenharmony_ci        return tmp
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ciclass Pointer(Node):
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci    ptr_ignore_list = ["ret", "elem"]
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci    def __init__(self, state, address, pname):
158bf215546Sopenharmony_ci        self.address = address
159bf215546Sopenharmony_ci        self.state = state
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci        # Check if address exists in list and if it is a return value address
162bf215546Sopenharmony_ci        t1 = address in state.ptr_list
163bf215546Sopenharmony_ci        if t1:
164bf215546Sopenharmony_ci            rname = state.ptr_type_list[address]
165bf215546Sopenharmony_ci            t2 = rname in self.ptr_ignore_list and pname not in self.ptr_ignore_list
166bf215546Sopenharmony_ci        else:
167bf215546Sopenharmony_ci            rname = pname
168bf215546Sopenharmony_ci            t2 = False
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci        # If address does NOT exist (add it), OR IS a ret value (update with new type)
171bf215546Sopenharmony_ci        if not t1 or t2:
172bf215546Sopenharmony_ci            # If previously set to ret value, remove one from count
173bf215546Sopenharmony_ci            if t1 and t2:
174bf215546Sopenharmony_ci                self.adjust_ptr_type_count(rname, -1)
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci            # Add / update
177bf215546Sopenharmony_ci            self.adjust_ptr_type_count(pname, 1)
178bf215546Sopenharmony_ci            tmp = "{}_{}".format(pname, state.ptr_types_list[pname])
179bf215546Sopenharmony_ci            state.ptr_list[address] = tmp
180bf215546Sopenharmony_ci            state.ptr_type_list[address] = pname
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci    def adjust_ptr_type_count(self, pname, delta):
183bf215546Sopenharmony_ci        if pname not in self.state.ptr_types_list:
184bf215546Sopenharmony_ci            self.state.ptr_types_list[pname] = 0
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci        self.state.ptr_types_list[pname] += delta
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci    def named_address(self):
189bf215546Sopenharmony_ci        return self.state.ptr_list[self.address]
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci    def visit(self, visitor):
192bf215546Sopenharmony_ci        visitor.visit_pointer(self)
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci    def __hash__(self):
195bf215546Sopenharmony_ci        return hash(self.named_address())
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ciclass Call:
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci    def __init__(self, no, klass, method, args, ret, time):
201bf215546Sopenharmony_ci        self.no = no
202bf215546Sopenharmony_ci        self.klass = klass
203bf215546Sopenharmony_ci        self.method = method
204bf215546Sopenharmony_ci        self.args = args
205bf215546Sopenharmony_ci        self.ret = ret
206bf215546Sopenharmony_ci        self.time = time
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci        # Calculate hashvalue "cached" into a variable
209bf215546Sopenharmony_ci        self.hashvalue = hash(self.klass) ^ hash(self.method)
210bf215546Sopenharmony_ci        for mname, mobj in self.args:
211bf215546Sopenharmony_ci            self.hashvalue = self.hashvalue ^ hash(mname) ^ hash(mobj)
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci    def visit(self, visitor):
214bf215546Sopenharmony_ci        visitor.visit_call(self)
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci    def __hash__(self):
217bf215546Sopenharmony_ci        return self.hashvalue
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci    def __eq__(self, other):
220bf215546Sopenharmony_ci        return self.hashvalue == other.hashvalue
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ciclass Trace:
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci    def __init__(self, calls):
226bf215546Sopenharmony_ci        self.calls = calls
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci    def visit(self, visitor):
229bf215546Sopenharmony_ci        visitor.visit_trace(self)
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ciclass Visitor:
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci    def visit_literal(self, node):
235bf215546Sopenharmony_ci        raise NotImplementedError
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci    def visit_blob(self, node):
238bf215546Sopenharmony_ci        raise NotImplementedError
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci    def visit_named_constant(self, node):
241bf215546Sopenharmony_ci        raise NotImplementedError
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci    def visit_array(self, node):
244bf215546Sopenharmony_ci        raise NotImplementedError
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci    def visit_struct(self, node):
247bf215546Sopenharmony_ci        raise NotImplementedError
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci    def visit_pointer(self, node):
250bf215546Sopenharmony_ci        raise NotImplementedError
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci    def visit_call(self, node):
253bf215546Sopenharmony_ci        raise NotImplementedError
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci    def visit_trace(self, node):
256bf215546Sopenharmony_ci        raise NotImplementedError
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ciclass PrettyPrinter:
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci    def __init__(self, formatter, options):
262bf215546Sopenharmony_ci        self.formatter = formatter
263bf215546Sopenharmony_ci        self.options = options
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci    def visit_literal(self, node):
266bf215546Sopenharmony_ci        if node.value is None:
267bf215546Sopenharmony_ci            self.formatter.literal('NULL')
268bf215546Sopenharmony_ci            return
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci        if isinstance(node.value, str):
271bf215546Sopenharmony_ci            self.formatter.literal('"' + node.value + '"')
272bf215546Sopenharmony_ci            return
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci        self.formatter.literal(repr(node.value))
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci    def visit_blob(self, node):
277bf215546Sopenharmony_ci        self.formatter.address('blob()')
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci    def visit_named_constant(self, node):
280bf215546Sopenharmony_ci        self.formatter.literal(node.name)
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci    def visit_array(self, node):
283bf215546Sopenharmony_ci        self.formatter.text('{')
284bf215546Sopenharmony_ci        sep = ''
285bf215546Sopenharmony_ci        for value in node.elements:
286bf215546Sopenharmony_ci            self.formatter.text(sep)
287bf215546Sopenharmony_ci            value.visit(self)
288bf215546Sopenharmony_ci            sep = ', '
289bf215546Sopenharmony_ci        self.formatter.text('}')
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci    def visit_struct(self, node):
292bf215546Sopenharmony_ci        self.formatter.text('{')
293bf215546Sopenharmony_ci        sep = ''
294bf215546Sopenharmony_ci        for name, value in node.members:
295bf215546Sopenharmony_ci            self.formatter.text(sep)
296bf215546Sopenharmony_ci            self.formatter.variable(name)
297bf215546Sopenharmony_ci            self.formatter.text(' = ')
298bf215546Sopenharmony_ci            value.visit(self)
299bf215546Sopenharmony_ci            sep = ', '
300bf215546Sopenharmony_ci        self.formatter.text('}')
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci    def visit_pointer(self, node):
303bf215546Sopenharmony_ci        if self.options.named_ptrs:
304bf215546Sopenharmony_ci            self.formatter.address(node.named_address())
305bf215546Sopenharmony_ci        else:
306bf215546Sopenharmony_ci            self.formatter.address(node.address)
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci    def visit_call(self, node):
309bf215546Sopenharmony_ci        if not self.options.suppress_variants:
310bf215546Sopenharmony_ci            self.formatter.text(f'{node.no} ')
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci        if node.klass is not None:
313bf215546Sopenharmony_ci            self.formatter.function(node.klass + '::' + node.method)
314bf215546Sopenharmony_ci        else:
315bf215546Sopenharmony_ci            self.formatter.function(node.method)
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci        if not self.options.method_only:
318bf215546Sopenharmony_ci            self.formatter.text('(')
319bf215546Sopenharmony_ci            sep = ''
320bf215546Sopenharmony_ci            for name, value in node.args:
321bf215546Sopenharmony_ci                self.formatter.text(sep)
322bf215546Sopenharmony_ci                self.formatter.variable(name)
323bf215546Sopenharmony_ci                self.formatter.text(' = ')
324bf215546Sopenharmony_ci                value.visit(self)
325bf215546Sopenharmony_ci                sep = ', '
326bf215546Sopenharmony_ci            self.formatter.text(')')
327bf215546Sopenharmony_ci            if node.ret is not None:
328bf215546Sopenharmony_ci                self.formatter.text(' = ')
329bf215546Sopenharmony_ci                node.ret.visit(self)
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci        if not self.options.suppress_variants and node.time is not None:
332bf215546Sopenharmony_ci            self.formatter.text(' // time ')
333bf215546Sopenharmony_ci            node.time.visit(self)
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci        self.formatter.newline()
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci    def visit_trace(self, node):
338bf215546Sopenharmony_ci        for call in node.calls:
339bf215546Sopenharmony_ci            call.visit(self)
340bf215546Sopenharmony_ci
341