2 Debugging utilities for constructs
4 from __future__ import print_function
9 from .core import Construct, Subconstruct
10 from .lib import HexString, Container, ListContainer
13 class Probe(Construct):
15 A probe: dumps the context, stack frames, and stream content to the screen
16 to aid the debugging process.
20 * name - the display name
21 * show_stream - whether or not to show stream contents. default is True.
22 the stream must be seekable.
23 * show_context - whether or not to show the context. default is True.
24 * show_stack - whether or not to show the upper stack frames. default
26 * stream_lookahead - the number of bytes to dump when show_stack is set.
32 Probe("between a and b"),
37 "printname", "show_stream", "show_context", "show_stack",
42 def __init__(self, name = None, show_stream = True,
43 show_context = True, show_stack = True,
44 stream_lookahead = 100):
45 Construct.__init__(self, None)
48 name = "<unnamed %d>" % (Probe.counter,)
50 self.show_stream = show_stream
51 self.show_context = show_context
52 self.show_stack = show_stack
53 self.stream_lookahead = stream_lookahead
55 return "%s(%r)" % (self.__class__.__name__, self.printname)
56 def _parse(self, stream, context):
57 self.printout(stream, context)
58 def _build(self, obj, stream, context):
59 self.printout(stream, context)
60 def _sizeof(self, context):
63 def printout(self, stream, context):
66 obj.stream_position = stream.tell()
67 follows = stream.read(self.stream_lookahead)
69 obj.following_stream_data = "EOF reached"
71 stream.seek(-len(follows), 1)
72 obj.following_stream_data = HexString(follows)
79 obj.stack = ListContainer()
80 frames = [s[0] for s in inspect.stack()][1:-1]
84 a.__update__(f.f_locals)
88 print("Probe", self.printname)
92 class Debugger(Subconstruct):
94 A pdb-based debugger. When an exception occurs in the subcon, a debugger
95 will appear and allow you to debug the error (and even fix on-the-fly).
98 * subcon - the subcon to debug
109 __slots__ = ["retval"]
110 def _parse(self, stream, context):
112 return self.subcon._parse(stream, context)
114 self.retval = NotImplemented
115 self.handle_exc("(you can set the value of 'self.retval', "
116 "which will be returned)")
117 if self.retval is NotImplemented:
121 def _build(self, obj, stream, context):
123 self.subcon._build(obj, stream, context)
126 def handle_exc(self, msg = None):
128 print("Debugging exception of %s:" % (self.subcon,))
129 print("".join(traceback.format_exception(*sys.exc_info())[1:]))
132 pdb.post_mortem(sys.exc_info()[2])