Repository navigation
Expand file tree
/
Copy pathdebug.py
More file actions
151 lines (124 loc) · 4.5 KB
/
Copy pathdebug.py
File metadata and controls
151 lines (124 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
"""
PC-BASIC - debug.py
DEBUG statement and utilities
(c) 2013--2023 Rob Hagemans
This file is released under the GNU GPL version 3 or later.
"""
import io
import sys
import logging
import struct
from .basic.base import error
from .compat import PY2, text_type
from .info import get_platform_info
from .basic import values, api
class DebugException(BaseException):
"""This exception was raised deliberately through the debug module."""
# inherit from BaseException to circumvent extension manager catching Exception
def __repr__(self):
return self.__doc__
__str__ = __repr__
class DebugSession(api.Session):
"""Debugging helper."""
def __init__(self, *args, **kwargs):
"""Initialise debugger."""
# register as an extension
kwargs['extension'] = tuple(kwargs.get('extension', ())) + (self,)
api.Session.__init__(self, *args, **kwargs)
def start(self):
"""Start the session."""
# initialise implementation
if api.Session.start(self):
# replace dummy debugging step
self.set_hook(self._debug_step)
self._do_trace = False
self._watch_list = []
def _debug_step(self, token):
"""Execute traces and watches on a program step."""
outstr = u''
if self._do_trace:
linum = struct.unpack_from('<H', token, 2)
outstr += u'[%i]' % linum
for expr in self._watch_list:
exprstr = self.convert(expr, to_type=text_type)
outstr += u' %s = ' % (exprstr,)
try:
val = self.evaluate(expr)
print(expr, val)
if isinstance(val, bytes):
outstr += u'"%s"' % self.convert(val, to_type=text_type)
else:
outstr += repr(val)
except Exception as e:
self._handle_exception(e)
if outstr:
logging.debug(outstr)
def _handle_exception(self, e):
"""Handle exception during debugging."""
logging.debug('%s %s', type(e), str(e))
raise
###########################################################################
# debugging commands
def dir(self):
"""Show debugging commands."""
logging.debug('Available commands:\n' + '\n'.join(
' _%s: %s' % (
n.upper(), getattr(self, n).__doc__)
for n in dir(self)
if '_' not in n and callable(getattr(self, n)) and n not in dir(api.Session)
))
def crash(self):
"""Simulate a crash."""
raise DebugException()
def python(self, cmd):
"""Execute any Python code."""
buf = io.BytesIO() if PY2 else io.StringIO()
save_stdout = sys.stdout
sys.stdout = buf
try:
exec(cmd)
except Exception as e:
self._handle_exception(e)
sys.stdout = save_stdout
logging.debug(buf.getvalue()[:-1]) # exclude \n
def restart(self):
"""Ctrl+Alt+Delete."""
raise error.Reset()
def exit(self):
"""Quit the session."""
raise error.Exit()
def logprint(self, *args):
"""Write arguments to log."""
logging.debug(self.convert(b' '.join(bytes(arg) for arg in args), to_type=text_type))
def logwrite(self, *args):
"""Write arguments to log."""
logging.debug(' '.join(repr(arg) for arg in args))
def trace(self, on=True):
"""Switch line number tracing on or off."""
self._do_trace = on
def watch(self, expr):
"""Add an expression to the watch list."""
self._watch_list.append(expr)
def showvariables(self):
"""Dump all variables to the log."""
repr_vars = '\n'.join((
'==== Scalars ='.ljust(100, '='),
self.info.repr_scalars(),
'==== Arrays ='.ljust(100, '='),
self.info.repr_arrays(),
'==== Strings ='.ljust(100, '='),
self.info.repr_strings(),
))
for s in repr_vars.split('\n'):
logging.debug(s)
def showscreen(self):
"""Copy the screen buffer to the log."""
for s in self.info.repr_text_screen().split('\n'):
logging.debug(s)
def showprogram(self):
"""Write a marked-up hex dump of the program to the log."""
for s in self.info.repr_program().split('\n'):
logging.debug(s)
def showplatform(self):
"""Show platform info."""
logging.debug(get_platform_info())