1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#!/usr/bin/env python
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org##########################################################################
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# All Rights Reserved.
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# Permission is hereby granted, free of charge, to any person obtaining a
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# copy of this software and associated documentation files (the
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# "Software"), to deal in the Software without restriction, including
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# without limitation the rights to use, copy, modify, merge, publish,
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# distribute, sub license, and/or sell copies of the Software, and to
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# permit persons to whom the Software is furnished to do so, subject to
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# the following conditions:
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# The above copyright notice and this permission notice (including the
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# next paragraph) shall be included in all copies or substantial portions
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# of the Software.
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org##########################################################################
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport sys
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport xml.parsers.expat
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport binascii
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport optparse
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgfrom model import *
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4)
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass XmlToken:
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self, type, name_or_data, attrs = None, line = None, column = None):
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF)
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.type = type
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.name_or_data = name_or_data
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.attrs = attrs
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.line = line
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.column = column
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __str__(self):
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.type == ELEMENT_START:
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return '<' + self.name_or_data + ' ...>'
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.type == ELEMENT_END:
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return '</' + self.name_or_data + '>'
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.type == CHARACTER_DATA:
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return self.name_or_data
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.type == EOF:
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return 'end of file'
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        assert 0
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass XmlTokenizer:
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    """Expat based XML tokenizer."""
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self, fp, skip_ws = True):
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.fp = fp
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.tokens = []
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.index = 0
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.final = False
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.skip_ws = skip_ws
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.character_pos = 0, 0
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.character_data = ''
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.parser = xml.parsers.expat.ParserCreate()
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.parser.StartElementHandler  = self.handle_element_start
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.parser.EndElementHandler    = self.handle_element_end
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.parser.CharacterDataHandler = self.handle_character_data
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def handle_element_start(self, name, attributes):
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.finish_character_data()
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        line, column = self.pos()
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        token = XmlToken(ELEMENT_START, name, attributes, line, column)
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.tokens.append(token)
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def handle_element_end(self, name):
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.finish_character_data()
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        line, column = self.pos()
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        token = XmlToken(ELEMENT_END, name, None, line, column)
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.tokens.append(token)
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def handle_character_data(self, data):
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if not self.character_data:
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.character_pos = self.pos()
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.character_data += data
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def finish_character_data(self):
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.character_data:
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if not self.skip_ws or not self.character_data.isspace():
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                line, column = self.character_pos
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column)
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                self.tokens.append(token)
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.character_data = ''
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def next(self):
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        size = 16*1024
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.index >= len(self.tokens) and not self.final:
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.tokens = []
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.index = 0
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            data = self.fp.read(size)
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.final = len(data) < size
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            data = data.rstrip('\0')
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            try:
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                self.parser.Parse(data, self.final)
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            except xml.parsers.expat.ExpatError, e:
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS:
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                if e.code == 3:
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    pass
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                else:
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    raise e
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.index >= len(self.tokens):
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            line, column = self.pos()
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            token = XmlToken(EOF, None, None, line, column)
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        else:
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            token = self.tokens[self.index]
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.index += 1
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return token
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def pos(self):
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass TokenMismatch(Exception):
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self, expected, found):
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.expected = expected
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.found = found
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __str__(self):
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found))
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass XmlParser:
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    """Base XML document parser."""
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self, fp):
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.tokenizer = XmlTokenizer(fp)
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.consume()
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def consume(self):
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.token = self.tokenizer.next()
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def match_element_start(self, name):
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return self.token.type == ELEMENT_START and self.token.name_or_data == name
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def match_element_end(self, name):
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return self.token.type == ELEMENT_END and self.token.name_or_data == name
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def element_start(self, name):
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type == CHARACTER_DATA:
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.consume()
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.token.type != ELEMENT_START:
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.token.name_or_data != name:
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        attrs = self.token.attrs
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.consume()
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return attrs
171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def element_end(self, name):
173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type == CHARACTER_DATA:
174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.consume()
175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.token.type != ELEMENT_END:
176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.token.name_or_data != name:
178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.consume()
180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def character_data(self, strip = True):
182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        data = ''
183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type == CHARACTER_DATA:
184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            data += self.token.name_or_data
185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.consume()
186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if strip:
187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            data = data.strip()
188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return data
189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass TraceParser(XmlParser):
192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self, fp):
194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        XmlParser.__init__(self, fp)
195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.last_call_no = 0
196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse(self):
198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('trace')
199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type not in (ELEMENT_END, EOF):
200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            call = self.parse_call()
201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.handle_call(call)
202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.token.type != EOF:
203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.element_end('trace')
204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_call(self):
206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        attrs = self.element_start('call')
207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        try:
208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            no = int(attrs['no'])
209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        except KeyError:
210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.last_call_no += 1
211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            no = self.last_call_no
212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        else:
213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.last_call_no = no
214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        klass = attrs['class']
215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        method = attrs['method']
216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        args = []
217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        ret = None
218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type == ELEMENT_START:
219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if self.token.name_or_data == 'arg':
220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                arg = self.parse_arg()
221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                args.append(arg)
222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            elif self.token.name_or_data == 'ret':
223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                ret = self.parse_ret()
224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            elif self.token.name_or_data == 'call':
225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                # ignore nested function calls
226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                self.parse_call()
227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            else:
228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                raise TokenMismatch("<arg ...> or <ret ...>", self.token)
229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('call')
230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Call(no, klass, method, args, ret)
232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_arg(self):
234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        attrs = self.element_start('arg')
235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        name = attrs['name']
236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = self.parse_value()
237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('arg')
238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return name, value
240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_ret(self):
242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        attrs = self.element_start('ret')
243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = self.parse_value()
244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('ret')
245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return value
247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_value(self):
249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes')
250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if self.token.type == ELEMENT_START:
251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if self.token.name_or_data in expected_tokens:
252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                method = getattr(self, 'parse_' +  self.token.name_or_data)
253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                return method()
254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        raise TokenMismatch(" or " .join(expected_tokens), self.token)
255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_null(self):
257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('null')
258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('null')
259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(None)
260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_bool(self):
262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('bool')
263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = int(self.character_data())
264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('bool')
265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(value)
266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_int(self):
268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('int')
269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = int(self.character_data())
270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('int')
271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(value)
272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_uint(self):
274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('uint')
275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = int(self.character_data())
276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('uint')
277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(value)
278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_float(self):
280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('float')
281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = float(self.character_data())
282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('float')
283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(value)
284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_enum(self):
286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('enum')
287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        name = self.character_data()
288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('enum')
289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return NamedConstant(name)
290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_string(self):
292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('string')
293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = self.character_data()
294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('string')
295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(value)
296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_bytes(self):
298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('bytes')
299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = binascii.a2b_hex(self.character_data())
300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('bytes')
301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Literal(value)
302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_array(self):
304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('array')
305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        elems = []
306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type != ELEMENT_END:
307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            elems.append(self.parse_elem())
308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('array')
309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Array(elems)
310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_elem(self):
312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('elem')
313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = self.parse_value()
314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('elem')
315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return value
316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_struct(self):
318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        attrs = self.element_start('struct')
319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        name = attrs['name']
320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        members = []
321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        while self.token.type != ELEMENT_END:
322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            members.append(self.parse_member())
323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('struct')
324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Struct(name, members)
325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_member(self):
327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        attrs = self.element_start('member')
328f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        name = attrs['name']
329f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        value = self.parse_value()
330f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('member')
331f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
332f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return name, value
333f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
334f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def parse_ptr(self):
335f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_start('ptr')
336f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        address = self.character_data()
337f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.element_end('ptr')
338f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
339f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return Pointer(address)
340f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
341f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def handle_call(self, call):
342f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        pass
343f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
344f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
345f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass TraceDumper(TraceParser):
346f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
347f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self, fp):
348f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        TraceParser.__init__(self, fp)
349f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.formatter = format.DefaultFormatter(sys.stdout)
350f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.pretty_printer = PrettyPrinter(self.formatter)
351f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
352f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def handle_call(self, call):
353f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        call.visit(self.pretty_printer)
354f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        self.formatter.newline()
355f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
356f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
357f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass Main:
358f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    '''Common main class for all retrace command line utilities.'''
359f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
360f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def __init__(self):
361f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        pass
362f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
363f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def main(self):
364f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        optparser = self.get_optparser()
365f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        (options, args) = optparser.parse_args(sys.argv[1:])
366f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
367f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        if args:
368f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            for arg in args:
369f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                if arg.endswith('.gz'):
370f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    from gzip import GzipFile
371f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    stream = GzipFile(arg, 'rt')
372f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                elif arg.endswith('.bz2'):
373f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    from bz2 import BZ2File
374f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    stream = BZ2File(arg, 'rU')
375f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                else:
376f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    stream = open(arg, 'rt')
377f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                self.process_arg(stream, options)
378f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        else:
379f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            self.process_arg(stream, options)
380f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
381f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def get_optparser(self):
382f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        optparser = optparse.OptionParser(
383f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            usage="\n\t%prog [options] [traces] ...")
384f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        return optparser
385f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
386f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    def process_arg(self, stream, options):
387f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        parser = TraceDumper(stream)
388f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        parser.parse()
389f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
390f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
391f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgif __name__ == '__main__':
392f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    Main().main()
393