Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
kmaork committed Oct 20, 2022
1 parent 890fc1e commit 84f7894
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 162 deletions.
57 changes: 42 additions & 15 deletions madbg/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@
import runpy
import os
import sys
from asyncio import AbstractEventLoop
from bdb import BdbQuit
from contextlib import contextmanager, nullcontext
from threading import Thread
from typing import ContextManager
from hypno import run_in_thread
from prompt_toolkit.formatted_text import PygmentsTokens
from prompt_toolkit.input.vt100 import Vt100Input
from prompt_toolkit.output.vt100 import Vt100_Output
from IPython.terminal.debugger import TerminalPdb
from IPython.terminal.interactiveshell import TerminalInteractiveShell
from pygments.token import Token

from .inject_into_main_thread import inject
from .utils import preserve_sys_state, Singleton
from .utils import preserve_sys_state
from .tty_utils import PTY, TTYConfig, print_to_ctty


def get_running_app(term_input, term_output):
def get_running_app(debugger):
from prompt_toolkit import PromptSession
from prompt_toolkit.key_binding import KeyBindings
kb = KeyBindings()
Expand All @@ -26,14 +30,14 @@ def handle_ctrl_c(_event):
# This is what happens in the parent, is it equivalent?
# self.set_step()
# self.set_trace(frame)
inject()
debugger.attach()

pt_app = PromptSession(
# message=(lambda: PygmentsTokens(get_prompt_tokens())),
# editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
key_bindings=kb,
input=term_input,
output=term_output,
input=debugger.term_input,
output=debugger.term_output,
# TODO: ctrl-r still works??
enable_history_search=False,
# history=self.debugger_history,
Expand All @@ -47,35 +51,59 @@ def handle_ctrl_c(_event):
return pt_app


class RemoteIPythonDebugger(TerminalPdb, metaclass=Singleton):
class RemoteIPythonDebugger(TerminalPdb):
_DEBUGGING_GLOBAL = 'DEBUGGING_WITH_MADBG'
_INSTANCES = {}

def __init__(self):
def __init__(self, thread: Thread, loop: AbstractEventLoop):
"""
Private constructor, use get_instance.
"""
self.pty = PTY.open()
self.pty.set_raw()
# A patch until https://github.com/ipython/ipython/issues/11745 is solved
TerminalInteractiveShell.simple_prompt = False
self.term_input = Vt100Input(self.pty.slave_reader)
self.term_output = Vt100_Output.from_pty(self.pty.slave_writer)
super().__init__(pt_session_options=dict(input=self.term_input, output=self.term_output),
super().__init__(pt_session_options=dict(input=self.term_input, output=self.term_output,
message=self._get_prompt),
stdin=self.pty.slave_reader, stdout=self.pty.slave_writer, nosigint=True)
self.use_rawinput = True
self.num_clients = 0
self.done_callbacks = set()
# TODO: this should be intercepted on the client side to allow force quitting the client
self.pt_app.key_bindings.remove("c-\\")
self.running_app = get_running_app(self.term_input, self.term_output)
self.thread = thread
self.loop = loop
# todo: run main debugger prompt in our loop
self.running_app = get_running_app(self)

@classmethod
def get_instance(cls, thread: Thread, loop: AbstractEventLoop):
instance = cls._INSTANCES.get(thread)
if instance is None:
instance = cls(thread, loop)
cls._INSTANCES[thread] = instance
return instance

def _get_prompt(self):
return PygmentsTokens([(Token.Prompt, f'{self.thread.name}> ')])

def __del__(self):
print('Closing connection', file=self.pty.slave_writer, flush=True)
self.pty.close()

def attach(self):
print(f'attaching {self.thread}')
run_in_thread(self.thread, self.set_trace)

def notify_client_connect(self, tty_config: TTYConfig):
self.num_clients += 1
if self.num_clients == 1:
tty_config.apply(self.pty.slave_fd)
self.term_output.term = tty_config.term_type
if self.num_clients == 1:
inject()
self.attach()

def notify_client_disconnect(self):
self.num_clients -= 1
Expand All @@ -89,7 +117,6 @@ def notify_client_disconnect(self):
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)

Expand Down Expand Up @@ -128,10 +155,10 @@ def _on_done(self):
self.done_callbacks.clear()

def do_continue(self, arg):
""" Overriding super to add a print """
print('Resuming program, press Ctrl-C to relaunch debugger.', file=self.stdout)
self._on_done()
# TODO: still got the history (c-r) - do we maybe want app run and not app prompt?
self.thread_executor.submit(self.running_app.prompt)
self.loop.call_soon_threadsafe(self.running_app.prompt_async)
# This doesn't register a SIGINT handler as we set self.nosigint to True
return super().do_continue(arg)

do_c = do_cont = do_continue
Expand Down
19 changes: 0 additions & 19 deletions madbg/inject_demo.py

This file was deleted.

27 changes: 0 additions & 27 deletions madbg/inject_into_main_thread.py

This file was deleted.

46 changes: 0 additions & 46 deletions madbg/inject_into_thread.py

This file was deleted.

Loading

0 comments on commit 84f7894

Please sign in to comment.