1#!/usr/bin/env python3 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