Skip to content

Commit

Permalink
Attach!
Browse files Browse the repository at this point in the history
  • Loading branch information
kmaork committed Sep 2, 2022
1 parent c4a103f commit 890fc1e
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 19 deletions.
2 changes: 0 additions & 2 deletions madbg/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import os
import re
import signal
import sys
from traceback import format_exc
from contextlib import nullcontext
Expand Down
2 changes: 2 additions & 0 deletions madbg/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
STDERR_FILENO = 2

DEFAULT_ADDR = ('127.0.0.1', 0xdb9)
# TODO: add flag to use unsafe injection
# TODO: for normal injection have infinite timeout
DEFAULT_CONNECT_TIMEOUT = 10.

MESSAGE_LENGTH_FMT = 'I'
Expand Down
12 changes: 10 additions & 2 deletions madbg/debugger.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
from __future__ import annotations
import runpy
import os
import signal
import sys
from bdb import BdbQuit
from contextlib import contextmanager, nullcontext
from typing import ContextManager
from prompt_toolkit.input.vt100 import Vt100Input
from prompt_toolkit.output.vt100 import Vt100_Output
from inspect import currentframe
from IPython.terminal.debugger import TerminalPdb
from IPython.terminal.interactiveshell import TerminalInteractiveShell

Expand Down Expand Up @@ -81,13 +79,19 @@ def notify_client_connect(self, tty_config: TTYConfig):

def notify_client_disconnect(self):
self.num_clients -= 1
print(0)
if self.num_clients == 0:
# TODO: can we use self.stop_here (from ipython code) instead of the debugging global?
print(1)
if self.pt_app.app.is_running:
print(2)
self.pt_app.app.exit('quit')
print(3)
elif self.running_app.app.is_running:
print(4)
# TODO: need to unregister the signal handler
self.running_app.app.exit()
print(5)

def preloop(self):
if self.num_clients == 0:
Expand All @@ -106,12 +110,16 @@ def trace_dispatch(self, frame, event, arg, check_debugging_global=False):
return None
bdb_quit = False
try:
print('a')
return super().trace_dispatch(frame, event, arg)
except BdbQuit:
bdb_quit = True
finally:
print('x')
if self.quitting or bdb_quit:
print('y')
self._on_done()
print('z')

def _on_done(self):
print_to_ctty('Debugger stopped')
Expand Down
30 changes: 17 additions & 13 deletions madbg/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import struct
from asyncio import Protocol, StreamReader, StreamWriter, AbstractEventLoop, start_server, new_event_loop, \
get_event_loop, Future
from dataclasses import dataclass, field
from threading import Thread
from typing import Any, Set

Expand All @@ -20,6 +21,11 @@
# own terminal size and type... This doesn't go hand in hand with the current IPythonDebugger
# design, as it assumes it is singletonic, and it has one output PTY.

@dataclass
class State:
address: tuple
future: Future = field(default_factory=Future)

class ClientMulticastProtocol(Protocol):
def __init__(self, loop: AbstractEventLoop):
self.loop: AbstractEventLoop = loop
Expand Down Expand Up @@ -120,33 +126,31 @@ def make_sure_listening_at(cls, addr: Addr):
with cls.STATE as state:
if state is None:
# TODO: receive addr as arg
cls.STATE.set(Future())
cls.STATE.set(State(addr))
debugger = RemoteIPythonDebugger()
prepare_injection(debugger)
Thread(daemon=True, target=cls._run, args=(addr, debugger)).start()
elif state.done():
elif state.future.done():
# Raise the exception
state.result()
state.future.result()
else:
# TODO
raise RuntimeError('No support for double bind')
if addr != state.address:
# TODO
raise RuntimeError('No support for double bind')


"""
Next steps:
- attach
need to do something very minimal during attach, like registering a signal handler or add pending action
pending action is better than another fucking signal, but it will wait for stuck syscalls...
pyinjector.pyinjector.InjectorError: injector_inject returned -1: The target process unexpectedly stopped by signal 17.
pyinjector issues:
- getting the python error back to us or at least know that it failed
- threads
- deadlock
- pyinjector issues:
- getting the python error back to us or at least know that it failed
- threads
- deadlock
- client-level detach (c-z, c-\)
- support mac n windows
python -c $'import madbg; madbg.start()\nwhile 1: print(__import__("time").sleep(1) or ":)")'
python -c $'while 1: print(__import__("time").sleep(1) or ":)")'
- There is only one debugger with one session
- A trace can start at any thread because of a set_trace(), or a client setting it
- A trace can start when there is no client connected, but should print a warning to tty
Expand Down
6 changes: 4 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ packages = madbg
python_requires = >=3.7
install_requires =
click
IPython>=7.17.0
# Need https://github.com/ipython/ipython/pull/13311
IPython>=7.30.0
prompt_toolkit
hypno>=0.1.3
# TODO
hypno>=1.1.0

[metadata]
name = madbg
Expand Down

0 comments on commit 890fc1e

Please sign in to comment.