2 ##########################################################################
4 # Copyright 2011 Jose Fonseca
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the 'Software'), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 ##########################################################################/
34 from cStringIO import StringIO
36 from StringIO import StringIO
41 class GzipFile(gzip.GzipFile):
44 # Ignore incomplete files
46 gzip.GzipFile._read_eof(self)
53 EVENT_ENTER, EVENT_LEAVE = range(2)
55 CALL_END, CALL_ARG, CALL_RET, CALL_THREAD = range(4)
57 TYPE_NULL, TYPE_FALSE, TYPE_TRUE, TYPE_SINT, TYPE_UINT, TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, TYPE_BLOB, TYPE_ENUM, TYPE_BITMASK, TYPE_ARRAY, TYPE_STRUCT, TYPE_OPAQUE = range(14)
61 '''Dummy class for signatures.'''
68 def visit(self, visitor):
69 raise NotImplementedError
71 def pretty_print(self, formatter):
72 pretty_printer = PrettyPrinter(formatter)
73 self.visit(pretty_printer)
77 formatter = format.Formatter(stream)
78 self.pretty_print(formatter)
79 return stream.getvalue()
81 def __eq__(self, other):
82 raise NotImplementedError
85 raise NotImplementedError
90 def __init__(self, value):
93 def visit(self, visitor):
94 visitor.visit_literal(self)
96 def __eq__(self, other):
98 self.__class__ == other.__class__ and \
99 self.value == other.value
102 return hash(self.value)
107 def __init__(self, name, value):
111 def visit(self, visitor):
112 visitor.visit_enum(self)
114 def __eq__(self, other):
116 self.__class__ == other.__class__ and \
117 self.name == other.name and \
118 self.value == other.value
121 return hash(self.value)
126 def __init__(self, elements):
127 self.elements = tuple(elements)
129 def visit(self, visitor):
130 visitor.visit_array(self)
132 def __eq__(self, other):
134 self.__class__ == other.__class__ and \
135 self.elements == other.elements
138 return hash(self.elements)
143 def __init__(self, value):
146 def visit(self, visitor):
147 visitor.visit_pointer(self)
149 def __eq__(self, other):
151 self.__class__ == other.__class__ and \
152 self.value == other.value
155 return hash(self.value)
159 return Enum("NULL", 0)
161 def Bitmask(sig, value):
162 return Literal(value)
165 return Literal('blob(%u)' % len(buf))
170 def __init__(self, sig, members):
172 self.members = tuple(members)
174 def visit(self, visitor):
175 visitor.visit_struct(self)
177 def __eq__(self, other):
179 self.__class__ == other.__class__ and \
180 self.sig.member_names == other.sig.member_names and \
181 self.members == other.members
184 return hash(self.sig.member_names) ^ hash(self.members)
189 def __init__(self, sig):
191 self.args = [None] * len(sig.arg_names)
197 name = property(get_name)
199 def visit(self, visitor):
200 visitor.visit_call(self)
202 def __eq__(self, other):
204 self.__class__ == other.__class__ and \
205 self.sig.name == other.sig.name and \
206 self.args == other.args and \
207 self.ret == other.ret
210 return hash(self.sig.name) ^ hash(tuple(self.args)) ^ hash(self.ret)
215 def __init__(self, calls):
218 def visit(self, visitor):
219 visitor.visit_trace(self)
224 def visit_literal(self, node):
225 raise NotImplementedError
227 def visit_enum(self, node):
228 raise NotImplementedError
230 def visit_array(self, node):
231 raise NotImplementedError
233 def visit_struct(self, node):
234 raise NotImplementedError
236 def visit_pointer(self, node):
237 raise NotImplementedError
239 def visit_call(self, node):
240 raise NotImplementedError
242 def visit_trace(self, node):
243 raise NotImplementedError
248 def __init__(self, formatter):
249 self.formatter = formatter
251 def visit_literal(self, node):
252 if isinstance(node.value, basestring):
253 if len(node.value) >= 4096 or node.value.strip(string.printable):
254 self.formatter.text('...')
257 self.formatter.literal('"' + node.value + '"')
260 self.formatter.literal(repr(node.value))
262 def visit_enum(self, node):
263 self.formatter.literal(node.name)
265 def visit_array(self, node):
266 self.formatter.text('{')
268 for value in node.elements:
269 self.formatter.text(sep)
272 self.formatter.text('}')
274 def visit_struct(self, node):
275 self.formatter.text('{')
277 for name, value in zip(node.sig.member_names, node.members):
278 self.formatter.text(sep)
279 self.formatter.variable(name)
280 self.formatter.text(' = ')
283 self.formatter.text('}')
285 def visit_pointer(self, node):
286 self.formatter.address(node.value)
288 def visit_call(self, node):
289 #self.formatter.text('%s ' % node.no)
290 self.formatter.function(node.name)
291 self.formatter.text('(')
293 for name, value in zip(node.sig.arg_names, node.args):
294 self.formatter.text(sep)
295 self.formatter.variable(name)
296 self.formatter.text(' = ')
299 self.formatter.text(')')
300 if node.ret is not None:
301 self.formatter.text(' = ')
304 def visit_trace(self, node):
305 for call in node.calls:
307 self.formatter.newline()
314 self.next_call_no = 0
324 def open(self, filename):
325 self.file = GzipFile(filename, "rb")
329 version = self.read_uint()
330 if version > TRACE_VERSION:
331 sys.stderr.write("error: unsupported trace format version %u\n" % version)
336 def parse_call(self):
341 elif c == EVENT_LEAVE:
342 return self.parse_leave()
346 sys.stderr.write("error: unknown event %i\n" % c)
349 def parse_enter(self):
350 id = self.read_uint()
353 sig = self.functions[id]
356 sig.name = self.read_string()
357 num_args = self.read_uint()
358 sig.arg_names = tuple([self.read_string() for i in range(num_args)])
359 self.functions[id] = sig
362 call.no = self.next_call_no
363 self.next_call_no += 1
365 if self.parse_call_details(call):
366 self.calls.append(call)
370 def parse_leave(self):
371 call_no = self.read_uint()
373 for i in range(len(self.calls)):
374 if self.calls[i].no == call_no:
375 call = self.calls.pop(i)
380 if self.parse_call_details(call):
386 def parse_call_details(self, call):
394 call.ret = self.parse_value()
396 sys.stderr.write("error: unknown call detail %i\n" % c)
399 def parse_arg(self, call):
400 index = self.read_uint()
401 value = self.parse_value()
402 if index >= len(call.args):
403 call.args.resize(index + 1)
404 call.args[index] = value
406 def parse_value(self):
410 elif c == TYPE_FALSE:
411 value = Literal(False)
413 value = Literal(True)
415 value = self.parse_sint()
417 value = self.parse_uint()
418 elif c == TYPE_FLOAT:
419 value = self.parse_float()
420 elif c == TYPE_DOUBLE:
421 value = self.parse_double()
422 elif c == TYPE_STRING:
423 value = self.parse_string()
425 value = self.parse_enum()
426 elif c == TYPE_BITMASK:
427 value = self.parse_bitmask()
428 elif c == TYPE_ARRAY:
429 value = self.parse_array()
430 elif c == TYPE_STRUCT:
431 value = self.parse_struct()
433 value = self.parse_blob()
434 elif c == TYPE_OPAQUE:
435 value = self.parse_opaque()
437 sys.stderr.write("error: unknown type %i\n" % c)
439 #self.debug("\tVALUE %s\n" % value)
442 def parse_sint(self):
443 return Literal(-self.read_uint())
445 def parse_uint(self):
446 return Literal(self.read_uint())
448 def parse_float(self):
449 value = self.file.read(4)
450 value, = struct.unpack('f', value)
451 return Literal(value)
453 def parse_double(self):
454 value = self.file.read(8)
455 value, = struct.unpack('d', value)
456 return Literal(value)
458 def parse_string(self):
459 return Literal(self.read_string())
461 def parse_enum(self):
462 id = self.read_uint()
464 enum = self.enums[id]
466 name = self.read_string()
467 value = self.parse_value()
468 enum = Enum(name, value)
469 self.enums[id] = enum
472 def parse_bitmask(self):
473 id = self.read_uint()
475 sig = self.bitmasks[id]
478 num_flags = self.read_uint()
480 for i in range(num_flags):
481 name = self.read_string()
482 value = self.read_uint()
484 sys.stderr.write("warning: bitmask %s is zero but is not first flag\n" % name)
486 sig.flags.append(flag)
487 self.bitmasks[id] = sig
490 value = self.read_uint()
492 return Bitmask(sig, value)
494 def parse_array(self):
495 size = self.read_uint()
496 elements = [self.parse_value() for i in range(size)]
497 return Array(elements)
499 def parse_blob(self):
500 size = self.read_uint()
502 buf = self.file.read(size)
507 def parse_struct(self):
508 id = self.read_uint()
511 sig = self.structs[id]
514 sig.name = self.read_string()
515 num_members = self.read_uint()
516 sig.member_names = tuple([self.read_string() for i in range(num_members)])
517 self.structs[id] = sig
519 members = [self.parse_value() for i in range(len(sig.member_names))]
520 value = Struct(sig, members)
524 def parse_opaque(self):
525 addr = self.read_uint()
528 def read_string(self):
529 size = self.read_uint()
531 value = self.file.read(size)
534 #self.debug("\tSTRING \"%s\"\n" % value)
541 c = self.file.read(1)
545 value |= (c & 0x7f) << shift
549 #self.debug("\tUINT %u\n" % value)
553 c = self.file.read(1)
555 #self.debug("\tEOF\n")
559 #self.debug("\tBYTE 0x%x\n" % c)
567 formatter = format.DefaultFormatter(sys.stdout)
568 for arg in sys.argv[1:]:
571 call = parser.parse_call()
573 formatter.text('%u ' % call.no)
574 call.pretty_print(formatter)
576 call = parser.parse_call()
579 if __name__ == '__main__':