kalong 0.5.3__tar.gz → 0.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kalong-0.5.3 → kalong-0.5.4}/PKG-INFO +1 -1
- {kalong-0.5.3 → kalong-0.5.4}/kalong/__init__.py +16 -19
- {kalong-0.5.3 → kalong-0.5.4}/kalong/communication.py +40 -36
- {kalong-0.5.3 → kalong-0.5.4}/kalong/loops.py +1 -1
- {kalong-0.5.3 → kalong-0.5.4}/kalong/server.py +30 -28
- kalong-0.5.4/kalong/static/assets/index-DPZ8eRPa.js +229 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/static/index.html +1 -1
- {kalong-0.5.3 → kalong-0.5.4}/kalong/stepping.py +1 -2
- {kalong-0.5.3 → kalong-0.5.4}/kalong/websockets.py +17 -16
- {kalong-0.5.3 → kalong-0.5.4}/pyproject.toml +6 -19
- kalong-0.5.3/kalong/static/assets/index-B6z5WP1H.js +0 -226
- {kalong-0.5.3 → kalong-0.5.4}/.gitignore +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/LICENSE +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/README.md +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/__main__.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/config.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/debugger.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/errors.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/forking.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/static/assets/FiraCode-Bold-Ba6ukUQM.otf +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/static/assets/FiraCode-Regular-DP3ilQdk.otf +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/static/assets/favicon-rdSYpj7B.svg +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/tracing.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/utils/__init__.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/utils/doc_lookup/__init__.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/utils/doc_lookup/lookup.json +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/utils/io.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/utils/iterators.py +0 -0
- {kalong-0.5.3 → kalong-0.5.4}/kalong/utils/obj.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""A new take on debugging"""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.5.
|
|
3
|
+
__version__ = "0.5.4"
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
@@ -111,25 +111,22 @@ def main():
|
|
|
111
111
|
|
|
112
112
|
elif config.inject:
|
|
113
113
|
kalong_dir = Path(__file__).resolve().parent.parent
|
|
114
|
-
gdb_command = (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
# Releasing the GIL with the PyGILState_Ensure handle:
|
|
128
|
-
"(void) PyGILState_Release($1)",
|
|
129
|
-
]
|
|
114
|
+
gdb_command = ["gdb", "-p", str(config.inject), "-batch"] + [
|
|
115
|
+
"-eval-command=call %s" % hook
|
|
116
|
+
for hook in [
|
|
117
|
+
"(int) PyGILState_Ensure()", # Getting the GIL
|
|
118
|
+
'(int) PyRun_SimpleString("'
|
|
119
|
+
f"print('* Kalong injection from {os.getpid()} *');"
|
|
120
|
+
"import sys;" # Putting kalong project directory in sys path:
|
|
121
|
+
f"sys.path.insert(0, '{kalong_dir}');"
|
|
122
|
+
"import kalong;" # Setting breakpoint:
|
|
123
|
+
"kalong.break_above(2);"
|
|
124
|
+
'")',
|
|
125
|
+
# Releasing the GIL with the PyGILState_Ensure handle:
|
|
126
|
+
"(void) PyGILState_Release($1)",
|
|
130
127
|
]
|
|
131
|
-
|
|
132
|
-
print(f
|
|
128
|
+
]
|
|
129
|
+
print(f"Running: {' '.join(gdb_command)}")
|
|
133
130
|
run(gdb_command)
|
|
134
131
|
|
|
135
132
|
else:
|
|
@@ -25,7 +25,7 @@ from .errors import SetFrameError
|
|
|
25
25
|
from .loops import get_loop
|
|
26
26
|
from .stepping import add_step, clear_step, stop_trace
|
|
27
27
|
from .utils import basicConfig, get_file_from_code
|
|
28
|
-
from .websockets import die, websocket_state
|
|
28
|
+
from .websockets import adie, die, websocket_state
|
|
29
29
|
|
|
30
30
|
log = logging.getLogger(__name__)
|
|
31
31
|
basicConfig(level=config.log_level)
|
|
@@ -161,7 +161,7 @@ async def handle_message(ws, data, frame, event, arg):
|
|
|
161
161
|
elif command == "stop":
|
|
162
162
|
clear_step()
|
|
163
163
|
stop_trace(frame)
|
|
164
|
-
|
|
164
|
+
await adie()
|
|
165
165
|
else:
|
|
166
166
|
step_frame = get_frame(frame, data.get("frame"), tb)
|
|
167
167
|
add_step(command, step_frame)
|
|
@@ -194,42 +194,46 @@ async def communication_loop(frame_, event_, arg_, pending=None):
|
|
|
194
194
|
# Otherwise if it's new, just wait for HELLO to answer current state
|
|
195
195
|
|
|
196
196
|
stop = False
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
197
|
+
try:
|
|
198
|
+
async for msg in ws:
|
|
199
|
+
if msg.type == WSMsgType.TEXT:
|
|
200
|
+
data = json.loads(msg.data)
|
|
201
|
+
try:
|
|
202
|
+
response = await handle_message(ws, data, frame, event, arg)
|
|
203
|
+
except Exception as e:
|
|
204
|
+
log.error(f"Error handling message {data}", exc_info=e)
|
|
205
|
+
response = {
|
|
206
|
+
"type": "SET_ANSWER",
|
|
207
|
+
"prompt": data.get("prompt", "?").strip(),
|
|
208
|
+
"key": data.get("key"),
|
|
209
|
+
"command": data.get("command"),
|
|
210
|
+
"frame": data.get("frame"),
|
|
211
|
+
"answer": [serialize_exception(*sys.exc_info(), "internal")],
|
|
212
|
+
}
|
|
213
|
+
log.debug(f"Got {data} answering with {response}")
|
|
214
|
+
response["local"] = True
|
|
215
|
+
|
|
216
|
+
if response.pop("recursive", False):
|
|
217
|
+
await ws.send_json({"type": "PAUSE", "recursive": True})
|
|
218
|
+
await init(ws, frame, event, arg)
|
|
219
|
+
|
|
220
|
+
stop = response.pop("stop", False)
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
await ws.send_json(response)
|
|
224
|
+
except ConnectionResetError:
|
|
225
|
+
break
|
|
226
|
+
|
|
227
|
+
if stop:
|
|
228
|
+
break
|
|
229
|
+
|
|
230
|
+
elif msg.type == WSMsgType.ERROR:
|
|
231
|
+
log.error("WebSocket closed", exc_info=ws.exception())
|
|
227
232
|
break
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
log.error("WebSocket closed", exc_info=ws.exception())
|
|
231
|
-
break
|
|
233
|
+
except asyncio.CancelledError:
|
|
234
|
+
log.error("WebSocket communication cancelled")
|
|
232
235
|
|
|
233
236
|
# Browser exited, stopping debug if we are not stepping
|
|
234
237
|
if not stop:
|
|
235
238
|
stop_trace(frame)
|
|
239
|
+
await adie()
|
|
@@ -67,44 +67,46 @@ async def websocket(request):
|
|
|
67
67
|
log.debug(f"{side.title()} app connected for {origin}")
|
|
68
68
|
request.app[side][origin] = ws
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
break
|
|
81
|
-
if data["type"] == "DO_COMMAND":
|
|
82
|
-
if data["command"] in ["pause", "kill"]:
|
|
83
|
-
_, pid, _ = parse_origin(origin)
|
|
84
|
-
os.kill(
|
|
85
|
-
pid,
|
|
86
|
-
signal.SIGTERM if data["command"] == "kill" else USER_SIGNAL,
|
|
70
|
+
try:
|
|
71
|
+
async for msg in ws:
|
|
72
|
+
if msg.type == WSMsgType.TEXT:
|
|
73
|
+
data = json.loads(msg.data)
|
|
74
|
+
log.debug(f"{side} -> {other_side}: {data}")
|
|
75
|
+
try:
|
|
76
|
+
pair = await peer(request.app, other_side, origin)
|
|
77
|
+
except NoClientFoundError:
|
|
78
|
+
log.error(
|
|
79
|
+
f"No {human_readable_side(other_side)} connection was found, aborting debugger"
|
|
87
80
|
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
81
|
+
break
|
|
82
|
+
if data["type"] == "DO_COMMAND":
|
|
83
|
+
if data["command"] in ["pause", "kill"]:
|
|
84
|
+
_, pid, _ = parse_origin(origin)
|
|
85
|
+
sign = (
|
|
86
|
+
signal.SIGKILL if data["command"] == "kill" else USER_SIGNAL
|
|
87
|
+
)
|
|
88
|
+
log.info(f"Sending signal {sign} to {pid}")
|
|
89
|
+
os.kill(pid, sign)
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
await pair.send_json(data)
|
|
93
|
+
elif msg.type == WSMsgType.ERROR:
|
|
94
|
+
log.error(f"{side.title()} closed", exc_info=ws.exception())
|
|
95
|
+
except asyncio.CancelledError:
|
|
96
|
+
log.error(f"{side.title()} WebSocket communication cancelled")
|
|
93
97
|
|
|
94
98
|
log.debug(f"Closing {side}")
|
|
95
|
-
await ws.close()
|
|
96
99
|
|
|
97
100
|
if side in request.app and origin in request.app[side]:
|
|
98
|
-
|
|
101
|
+
request.app[side].pop(origin)
|
|
99
102
|
|
|
100
103
|
if not config.detached:
|
|
101
104
|
if origin in request.app[other_side]:
|
|
102
105
|
log.debug(f"Closing {other_side} due to {side} closing.")
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if origin in request.app[other_side]:
|
|
106
|
-
del request.app[other_side][origin]
|
|
106
|
+
s = request.app[other_side].pop(origin)
|
|
107
|
+
await s.close()
|
|
107
108
|
|
|
109
|
+
await ws.close()
|
|
108
110
|
maybe_bail(request.app)
|
|
109
111
|
return ws
|
|
110
112
|
|