17ec681f3Smrg#!/usr/bin/env python3 23464ebd5Sriastradh########################################################################## 33464ebd5Sriastradh# 4af69d88dSmrg# Copyright 2008 VMware, Inc. 53464ebd5Sriastradh# All Rights Reserved. 63464ebd5Sriastradh# 73464ebd5Sriastradh# Permission is hereby granted, free of charge, to any person obtaining a 83464ebd5Sriastradh# copy of this software and associated documentation files (the 93464ebd5Sriastradh# "Software"), to deal in the Software without restriction, including 103464ebd5Sriastradh# without limitation the rights to use, copy, modify, merge, publish, 113464ebd5Sriastradh# distribute, sub license, and/or sell copies of the Software, and to 123464ebd5Sriastradh# permit persons to whom the Software is furnished to do so, subject to 133464ebd5Sriastradh# the following conditions: 143464ebd5Sriastradh# 153464ebd5Sriastradh# The above copyright notice and this permission notice (including the 163464ebd5Sriastradh# next paragraph) shall be included in all copies or substantial portions 173464ebd5Sriastradh# of the Software. 183464ebd5Sriastradh# 193464ebd5Sriastradh# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 203464ebd5Sriastradh# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 213464ebd5Sriastradh# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22af69d88dSmrg# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 233464ebd5Sriastradh# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 243464ebd5Sriastradh# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 253464ebd5Sriastradh# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 263464ebd5Sriastradh# 273464ebd5Sriastradh########################################################################## 283464ebd5Sriastradh 293464ebd5Sriastradh 307ec681f3Smrgimport io 313464ebd5Sriastradhimport sys 327ec681f3Smrgimport xml.parsers.expat as xpat 337ec681f3Smrgimport argparse 343464ebd5Sriastradh 357ec681f3Smrgimport format 363464ebd5Sriastradhfrom model import * 373464ebd5Sriastradh 383464ebd5Sriastradh 393464ebd5SriastradhELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4) 403464ebd5Sriastradh 413464ebd5Sriastradh 423464ebd5Sriastradhclass XmlToken: 433464ebd5Sriastradh 443464ebd5Sriastradh def __init__(self, type, name_or_data, attrs = None, line = None, column = None): 453464ebd5Sriastradh assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF) 463464ebd5Sriastradh self.type = type 473464ebd5Sriastradh self.name_or_data = name_or_data 483464ebd5Sriastradh self.attrs = attrs 493464ebd5Sriastradh self.line = line 503464ebd5Sriastradh self.column = column 513464ebd5Sriastradh 523464ebd5Sriastradh def __str__(self): 533464ebd5Sriastradh if self.type == ELEMENT_START: 543464ebd5Sriastradh return '<' + self.name_or_data + ' ...>' 553464ebd5Sriastradh if self.type == ELEMENT_END: 563464ebd5Sriastradh return '</' + self.name_or_data + '>' 573464ebd5Sriastradh if self.type == CHARACTER_DATA: 583464ebd5Sriastradh return self.name_or_data 593464ebd5Sriastradh if self.type == EOF: 603464ebd5Sriastradh return 'end of file' 613464ebd5Sriastradh assert 0 623464ebd5Sriastradh 633464ebd5Sriastradh 643464ebd5Sriastradhclass XmlTokenizer: 653464ebd5Sriastradh """Expat based XML tokenizer.""" 663464ebd5Sriastradh 673464ebd5Sriastradh def __init__(self, fp, skip_ws = True): 683464ebd5Sriastradh self.fp = fp 693464ebd5Sriastradh self.tokens = [] 703464ebd5Sriastradh self.index = 0 713464ebd5Sriastradh self.final = False 723464ebd5Sriastradh self.skip_ws = skip_ws 733464ebd5Sriastradh 743464ebd5Sriastradh self.character_pos = 0, 0 753464ebd5Sriastradh self.character_data = '' 763464ebd5Sriastradh 777ec681f3Smrg self.parser = xpat.ParserCreate() 783464ebd5Sriastradh self.parser.StartElementHandler = self.handle_element_start 793464ebd5Sriastradh self.parser.EndElementHandler = self.handle_element_end 803464ebd5Sriastradh self.parser.CharacterDataHandler = self.handle_character_data 813464ebd5Sriastradh 823464ebd5Sriastradh def handle_element_start(self, name, attributes): 833464ebd5Sriastradh self.finish_character_data() 843464ebd5Sriastradh line, column = self.pos() 853464ebd5Sriastradh token = XmlToken(ELEMENT_START, name, attributes, line, column) 863464ebd5Sriastradh self.tokens.append(token) 873464ebd5Sriastradh 883464ebd5Sriastradh def handle_element_end(self, name): 893464ebd5Sriastradh self.finish_character_data() 903464ebd5Sriastradh line, column = self.pos() 913464ebd5Sriastradh token = XmlToken(ELEMENT_END, name, None, line, column) 923464ebd5Sriastradh self.tokens.append(token) 933464ebd5Sriastradh 943464ebd5Sriastradh def handle_character_data(self, data): 953464ebd5Sriastradh if not self.character_data: 963464ebd5Sriastradh self.character_pos = self.pos() 973464ebd5Sriastradh self.character_data += data 983464ebd5Sriastradh 993464ebd5Sriastradh def finish_character_data(self): 1003464ebd5Sriastradh if self.character_data: 1013464ebd5Sriastradh if not self.skip_ws or not self.character_data.isspace(): 1023464ebd5Sriastradh line, column = self.character_pos 1033464ebd5Sriastradh token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column) 1043464ebd5Sriastradh self.tokens.append(token) 1053464ebd5Sriastradh self.character_data = '' 1063464ebd5Sriastradh 1073464ebd5Sriastradh def next(self): 1083464ebd5Sriastradh size = 16*1024 1093464ebd5Sriastradh while self.index >= len(self.tokens) and not self.final: 1103464ebd5Sriastradh self.tokens = [] 1113464ebd5Sriastradh self.index = 0 1123464ebd5Sriastradh data = self.fp.read(size) 1133464ebd5Sriastradh self.final = len(data) < size 1143464ebd5Sriastradh data = data.rstrip('\0') 1153464ebd5Sriastradh try: 1163464ebd5Sriastradh self.parser.Parse(data, self.final) 1177ec681f3Smrg except xpat.ExpatError as e: 1187ec681f3Smrg #if e.code == xpat.errors.XML_ERROR_NO_ELEMENTS: 1193464ebd5Sriastradh if e.code == 3: 1203464ebd5Sriastradh pass 1213464ebd5Sriastradh else: 1223464ebd5Sriastradh raise e 1233464ebd5Sriastradh if self.index >= len(self.tokens): 1243464ebd5Sriastradh line, column = self.pos() 1253464ebd5Sriastradh token = XmlToken(EOF, None, None, line, column) 1263464ebd5Sriastradh else: 1273464ebd5Sriastradh token = self.tokens[self.index] 1283464ebd5Sriastradh self.index += 1 1293464ebd5Sriastradh return token 1303464ebd5Sriastradh 1313464ebd5Sriastradh def pos(self): 1323464ebd5Sriastradh return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber 1333464ebd5Sriastradh 1343464ebd5Sriastradh 1353464ebd5Sriastradhclass TokenMismatch(Exception): 1363464ebd5Sriastradh 1373464ebd5Sriastradh def __init__(self, expected, found): 1383464ebd5Sriastradh self.expected = expected 1393464ebd5Sriastradh self.found = found 1403464ebd5Sriastradh 1413464ebd5Sriastradh def __str__(self): 1423464ebd5Sriastradh return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found)) 1433464ebd5Sriastradh 1443464ebd5Sriastradh 1453464ebd5Sriastradh 1463464ebd5Sriastradhclass XmlParser: 1473464ebd5Sriastradh """Base XML document parser.""" 1483464ebd5Sriastradh 1493464ebd5Sriastradh def __init__(self, fp): 1503464ebd5Sriastradh self.tokenizer = XmlTokenizer(fp) 1513464ebd5Sriastradh self.consume() 1523464ebd5Sriastradh 1533464ebd5Sriastradh def consume(self): 1543464ebd5Sriastradh self.token = self.tokenizer.next() 1553464ebd5Sriastradh 1563464ebd5Sriastradh def match_element_start(self, name): 1573464ebd5Sriastradh return self.token.type == ELEMENT_START and self.token.name_or_data == name 1583464ebd5Sriastradh 1593464ebd5Sriastradh def match_element_end(self, name): 1603464ebd5Sriastradh return self.token.type == ELEMENT_END and self.token.name_or_data == name 1613464ebd5Sriastradh 1623464ebd5Sriastradh def element_start(self, name): 1633464ebd5Sriastradh while self.token.type == CHARACTER_DATA: 1643464ebd5Sriastradh self.consume() 1653464ebd5Sriastradh if self.token.type != ELEMENT_START: 1663464ebd5Sriastradh raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) 1673464ebd5Sriastradh if self.token.name_or_data != name: 1683464ebd5Sriastradh raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) 1693464ebd5Sriastradh attrs = self.token.attrs 1703464ebd5Sriastradh self.consume() 1713464ebd5Sriastradh return attrs 1723464ebd5Sriastradh 1733464ebd5Sriastradh def element_end(self, name): 1743464ebd5Sriastradh while self.token.type == CHARACTER_DATA: 1753464ebd5Sriastradh self.consume() 1763464ebd5Sriastradh if self.token.type != ELEMENT_END: 1773464ebd5Sriastradh raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) 1783464ebd5Sriastradh if self.token.name_or_data != name: 1793464ebd5Sriastradh raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) 1803464ebd5Sriastradh self.consume() 1813464ebd5Sriastradh 1823464ebd5Sriastradh def character_data(self, strip = True): 1833464ebd5Sriastradh data = '' 1843464ebd5Sriastradh while self.token.type == CHARACTER_DATA: 1853464ebd5Sriastradh data += self.token.name_or_data 1863464ebd5Sriastradh self.consume() 1873464ebd5Sriastradh if strip: 1883464ebd5Sriastradh data = data.strip() 1893464ebd5Sriastradh return data 1903464ebd5Sriastradh 1913464ebd5Sriastradh 1923464ebd5Sriastradhclass TraceParser(XmlParser): 1933464ebd5Sriastradh 1943464ebd5Sriastradh def __init__(self, fp): 1953464ebd5Sriastradh XmlParser.__init__(self, fp) 1963464ebd5Sriastradh self.last_call_no = 0 1973464ebd5Sriastradh 1983464ebd5Sriastradh def parse(self): 1993464ebd5Sriastradh self.element_start('trace') 2003464ebd5Sriastradh while self.token.type not in (ELEMENT_END, EOF): 2013464ebd5Sriastradh call = self.parse_call() 2023464ebd5Sriastradh self.handle_call(call) 2033464ebd5Sriastradh if self.token.type != EOF: 2043464ebd5Sriastradh self.element_end('trace') 2053464ebd5Sriastradh 2063464ebd5Sriastradh def parse_call(self): 2073464ebd5Sriastradh attrs = self.element_start('call') 2083464ebd5Sriastradh try: 2093464ebd5Sriastradh no = int(attrs['no']) 2107ec681f3Smrg except KeyError as e: 2113464ebd5Sriastradh self.last_call_no += 1 2123464ebd5Sriastradh no = self.last_call_no 2133464ebd5Sriastradh else: 2143464ebd5Sriastradh self.last_call_no = no 2153464ebd5Sriastradh klass = attrs['class'] 2163464ebd5Sriastradh method = attrs['method'] 2173464ebd5Sriastradh args = [] 2183464ebd5Sriastradh ret = None 219af69d88dSmrg time = None 2203464ebd5Sriastradh while self.token.type == ELEMENT_START: 2213464ebd5Sriastradh if self.token.name_or_data == 'arg': 2223464ebd5Sriastradh arg = self.parse_arg() 2233464ebd5Sriastradh args.append(arg) 2243464ebd5Sriastradh elif self.token.name_or_data == 'ret': 2253464ebd5Sriastradh ret = self.parse_ret() 2263464ebd5Sriastradh elif self.token.name_or_data == 'call': 2273464ebd5Sriastradh # ignore nested function calls 2283464ebd5Sriastradh self.parse_call() 229af69d88dSmrg elif self.token.name_or_data == 'time': 230af69d88dSmrg time = self.parse_time() 2313464ebd5Sriastradh else: 2323464ebd5Sriastradh raise TokenMismatch("<arg ...> or <ret ...>", self.token) 2333464ebd5Sriastradh self.element_end('call') 2343464ebd5Sriastradh 235af69d88dSmrg return Call(no, klass, method, args, ret, time) 2363464ebd5Sriastradh 2373464ebd5Sriastradh def parse_arg(self): 2383464ebd5Sriastradh attrs = self.element_start('arg') 2393464ebd5Sriastradh name = attrs['name'] 2407ec681f3Smrg value = self.parse_value(name) 2413464ebd5Sriastradh self.element_end('arg') 2423464ebd5Sriastradh 2433464ebd5Sriastradh return name, value 2443464ebd5Sriastradh 2453464ebd5Sriastradh def parse_ret(self): 2463464ebd5Sriastradh attrs = self.element_start('ret') 2477ec681f3Smrg value = self.parse_value('ret') 2483464ebd5Sriastradh self.element_end('ret') 2493464ebd5Sriastradh 2503464ebd5Sriastradh return value 2513464ebd5Sriastradh 252af69d88dSmrg def parse_time(self): 253af69d88dSmrg attrs = self.element_start('time') 2547ec681f3Smrg time = self.parse_value('time'); 255af69d88dSmrg self.element_end('time') 256af69d88dSmrg return time 257af69d88dSmrg 2587ec681f3Smrg def parse_value(self, name): 2593464ebd5Sriastradh expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes') 2603464ebd5Sriastradh if self.token.type == ELEMENT_START: 2613464ebd5Sriastradh if self.token.name_or_data in expected_tokens: 2623464ebd5Sriastradh method = getattr(self, 'parse_' + self.token.name_or_data) 2637ec681f3Smrg return method(name) 2643464ebd5Sriastradh raise TokenMismatch(" or " .join(expected_tokens), self.token) 2653464ebd5Sriastradh 2667ec681f3Smrg def parse_null(self, pname): 2673464ebd5Sriastradh self.element_start('null') 2683464ebd5Sriastradh self.element_end('null') 2693464ebd5Sriastradh return Literal(None) 2703464ebd5Sriastradh 2717ec681f3Smrg def parse_bool(self, pname): 2723464ebd5Sriastradh self.element_start('bool') 2733464ebd5Sriastradh value = int(self.character_data()) 2743464ebd5Sriastradh self.element_end('bool') 2753464ebd5Sriastradh return Literal(value) 2763464ebd5Sriastradh 2777ec681f3Smrg def parse_int(self, pname): 2783464ebd5Sriastradh self.element_start('int') 2793464ebd5Sriastradh value = int(self.character_data()) 2803464ebd5Sriastradh self.element_end('int') 2813464ebd5Sriastradh return Literal(value) 2823464ebd5Sriastradh 2837ec681f3Smrg def parse_uint(self, pname): 2843464ebd5Sriastradh self.element_start('uint') 2853464ebd5Sriastradh value = int(self.character_data()) 2863464ebd5Sriastradh self.element_end('uint') 2873464ebd5Sriastradh return Literal(value) 2883464ebd5Sriastradh 2897ec681f3Smrg def parse_float(self, pname): 2903464ebd5Sriastradh self.element_start('float') 2913464ebd5Sriastradh value = float(self.character_data()) 2923464ebd5Sriastradh self.element_end('float') 2933464ebd5Sriastradh return Literal(value) 2943464ebd5Sriastradh 2957ec681f3Smrg def parse_enum(self, pname): 2963464ebd5Sriastradh self.element_start('enum') 2973464ebd5Sriastradh name = self.character_data() 2983464ebd5Sriastradh self.element_end('enum') 2993464ebd5Sriastradh return NamedConstant(name) 3003464ebd5Sriastradh 3017ec681f3Smrg def parse_string(self, pname): 3023464ebd5Sriastradh self.element_start('string') 3033464ebd5Sriastradh value = self.character_data() 3043464ebd5Sriastradh self.element_end('string') 3053464ebd5Sriastradh return Literal(value) 3063464ebd5Sriastradh 3077ec681f3Smrg def parse_bytes(self, pname): 3083464ebd5Sriastradh self.element_start('bytes') 309af69d88dSmrg value = self.character_data() 3103464ebd5Sriastradh self.element_end('bytes') 311af69d88dSmrg return Blob(value) 3123464ebd5Sriastradh 3137ec681f3Smrg def parse_array(self, pname): 3143464ebd5Sriastradh self.element_start('array') 3153464ebd5Sriastradh elems = [] 3163464ebd5Sriastradh while self.token.type != ELEMENT_END: 3177ec681f3Smrg elems.append(self.parse_elem('array')) 3183464ebd5Sriastradh self.element_end('array') 3193464ebd5Sriastradh return Array(elems) 3203464ebd5Sriastradh 3217ec681f3Smrg def parse_elem(self, pname): 3223464ebd5Sriastradh self.element_start('elem') 3237ec681f3Smrg value = self.parse_value('elem') 3243464ebd5Sriastradh self.element_end('elem') 3253464ebd5Sriastradh return value 3263464ebd5Sriastradh 3277ec681f3Smrg def parse_struct(self, pname): 3283464ebd5Sriastradh attrs = self.element_start('struct') 3293464ebd5Sriastradh name = attrs['name'] 3303464ebd5Sriastradh members = [] 3313464ebd5Sriastradh while self.token.type != ELEMENT_END: 3327ec681f3Smrg members.append(self.parse_member(name)) 3333464ebd5Sriastradh self.element_end('struct') 3343464ebd5Sriastradh return Struct(name, members) 3353464ebd5Sriastradh 3367ec681f3Smrg def parse_member(self, pname): 3373464ebd5Sriastradh attrs = self.element_start('member') 3383464ebd5Sriastradh name = attrs['name'] 3397ec681f3Smrg value = self.parse_value(name) 3403464ebd5Sriastradh self.element_end('member') 3413464ebd5Sriastradh 3423464ebd5Sriastradh return name, value 3433464ebd5Sriastradh 3447ec681f3Smrg def parse_ptr(self, pname): 3453464ebd5Sriastradh self.element_start('ptr') 3463464ebd5Sriastradh address = self.character_data() 3473464ebd5Sriastradh self.element_end('ptr') 3483464ebd5Sriastradh 3497ec681f3Smrg return Pointer(address, pname) 3503464ebd5Sriastradh 3513464ebd5Sriastradh def handle_call(self, call): 3523464ebd5Sriastradh pass 3533464ebd5Sriastradh 3543464ebd5Sriastradh 3557ec681f3Smrgclass SimpleTraceDumper(TraceParser): 3563464ebd5Sriastradh 3577ec681f3Smrg def __init__(self, fp, options, formatter): 3583464ebd5Sriastradh TraceParser.__init__(self, fp) 3597ec681f3Smrg self.options = options 3607ec681f3Smrg self.formatter = formatter 3617ec681f3Smrg self.pretty_printer = PrettyPrinter(self.formatter, options) 3623464ebd5Sriastradh 3633464ebd5Sriastradh def handle_call(self, call): 3643464ebd5Sriastradh call.visit(self.pretty_printer) 3653464ebd5Sriastradh self.formatter.newline() 3667ec681f3Smrg 3677ec681f3Smrg 3687ec681f3Smrgclass TraceDumper(SimpleTraceDumper): 3697ec681f3Smrg 3707ec681f3Smrg def __init__(self, fp, options, formatter): 3717ec681f3Smrg SimpleTraceDumper.__init__(self, fp, options, formatter) 3727ec681f3Smrg self.call_stack = [] 3737ec681f3Smrg 3747ec681f3Smrg def handle_call(self, call): 3757ec681f3Smrg if self.options.named_ptrs: 3767ec681f3Smrg self.call_stack.append(call) 3777ec681f3Smrg else: 3787ec681f3Smrg call.visit(self.pretty_printer) 3797ec681f3Smrg self.formatter.newline() 3807ec681f3Smrg 3817ec681f3Smrg def dump_calls(self): 3827ec681f3Smrg for call in self.call_stack: 3837ec681f3Smrg call.visit(self.pretty_printer) 3847ec681f3Smrg self.formatter.newline() 3853464ebd5Sriastradh 3863464ebd5Sriastradh 3873464ebd5Sriastradhclass Main: 3883464ebd5Sriastradh '''Common main class for all retrace command line utilities.''' 3893464ebd5Sriastradh 3903464ebd5Sriastradh def __init__(self): 3913464ebd5Sriastradh pass 3923464ebd5Sriastradh 3933464ebd5Sriastradh def main(self): 3943464ebd5Sriastradh optparser = self.get_optparser() 3957ec681f3Smrg args = optparser.parse_args() 3967ec681f3Smrg 3977ec681f3Smrg for fname in args.filename: 3987ec681f3Smrg try: 3997ec681f3Smrg if fname.endswith('.gz'): 4007ec681f3Smrg from gzip import GzipFile 4017ec681f3Smrg stream = io.TextIOWrapper(GzipFile(fname, 'rb')) 4027ec681f3Smrg elif fname.endswith('.bz2'): 4037ec681f3Smrg from bz2 import BZ2File 4047ec681f3Smrg stream = io.TextIOWrapper(BZ2File(fname, 'rb')) 4057ec681f3Smrg else: 4067ec681f3Smrg stream = open(fname, 'rt') 4077ec681f3Smrg except Exception as e: 4087ec681f3Smrg print("ERROR: {}".format(str(e))) 4097ec681f3Smrg sys.exit(1) 4107ec681f3Smrg 4117ec681f3Smrg self.process_arg(stream, args) 4123464ebd5Sriastradh 4133464ebd5Sriastradh def get_optparser(self): 4147ec681f3Smrg optparser = argparse.ArgumentParser( 4157ec681f3Smrg description="Parse and dump Gallium trace(s)") 4167ec681f3Smrg optparser.add_argument("filename", action="extend", nargs="+", 4177ec681f3Smrg type=str, metavar="filename", help="Gallium trace filename (plain or .gz, .bz2)") 4187ec681f3Smrg optparser.add_argument("-p", "--plain", 4197ec681f3Smrg action="store_const", const=True, default=False, 4207ec681f3Smrg dest="plain", help="disable ANSI color etc. formatting") 4217ec681f3Smrg optparser.add_argument("-S", "--suppress", 4227ec681f3Smrg action="store_const", const=True, default=False, 4237ec681f3Smrg dest="suppress_variants", help="suppress some variants in output for better diffability") 4247ec681f3Smrg optparser.add_argument("-N", "--named", 4257ec681f3Smrg action="store_const", const=True, default=False, 4267ec681f3Smrg dest="named_ptrs", help="generate symbolic names for raw pointer values") 4277ec681f3Smrg optparser.add_argument("-M", "--method-only", 4287ec681f3Smrg action="store_const", const=True, default=False, 4297ec681f3Smrg dest="method_only", help="output only call names without arguments") 4307ec681f3Smrg 4313464ebd5Sriastradh return optparser 4323464ebd5Sriastradh 4333464ebd5Sriastradh def process_arg(self, stream, options): 4347ec681f3Smrg if options.plain: 4357ec681f3Smrg formatter = format.Formatter(sys.stdout) 4367ec681f3Smrg else: 4377ec681f3Smrg formatter = format.DefaultFormatter(sys.stdout) 4387ec681f3Smrg 4397ec681f3Smrg parser = TraceDumper(stream, options, formatter) 4403464ebd5Sriastradh parser.parse() 4413464ebd5Sriastradh 4427ec681f3Smrg if options.named_ptrs: 4437ec681f3Smrg parser.dump_calls() 4447ec681f3Smrg 4453464ebd5Sriastradh 4463464ebd5Sriastradhif __name__ == '__main__': 4473464ebd5Sriastradh Main().main() 448