Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attach to an existing running process #31

Closed
stenyak opened this issue Feb 1, 2012 · 10 comments · Fixed by #63
Closed

Attach to an existing running process #31

stenyak opened this issue Feb 1, 2012 · 10 comments · Fixed by #63

Comments

@stenyak
Copy link

stenyak commented Feb 1, 2012

It would be desirable to be able to attach to an already running python process, breaking its execution.
Similar to gdb -p

@iautom8things
Copy link

I would love to see this capability. I have only recently become fluent with gdb/lldb for my c++ code. I love pudb's interface, so this would be an invaluable tool for my mpi4py code.

@inducer
Copy link
Owner

inducer commented Feb 3, 2013

Do winpdb or pdb allow this? I'm not even sure how this could be done technically. In principle, one could break-and-enter the executing process using ptrace, execute a few Python functions to inject pudb and go from there. I won't have time to attack this for the foreseeable future, but if I anyone wants to take this one, I'd be happy to help.

@asmeurer
Copy link
Collaborator

Would it be enough to require that pudb already be imported in the process? If so, then I think this can be done relatively easily using signals. I checked, and something like

import signal, os

def handler(signum, frame):
    import pudb
    pudb.set_trace()

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGINT, handler)

def test():
    i = 0
    while True:
        i += 1
test()

works perfectly. In other words, if you run the script and type Ctrl-C, pudb starts up, and if you press n, it continues stepping where it left off. Instead of SIGINT, we could use any signal.

Some issues/notes:

  • What signal should we use? According to http://docs.python.org/2/library/signal.html, only the ones that are provided by the system are available, but that's quite a lot on POSIX. Are there any signals that are well suited for this problem? Will they all necessarily conflict? Is there a better message passing mechanism that we could use here?
  • According to that page, signals should only happen between atomic Python operations, but I wouldn't be surprised if there are still subtle issues with this.
  • We could implement this by putting a hook in pudb/__init__.py, but it would require someone to import pudb somewhere in their code first (which is perhaps not too much to ask, since you already have to do this anyway). We would also need to automatically jump the execution to the actual code, and not the signal handler.
  • If you press c, you will want to be able to stop it again. This probably actually should be done in a more general way, as that would be useful for all debugging. Probably the exact same mechanism will need to be used (unless bdb makes it easy to do this if the code is already being continued from within PuDB, I don't know).

asmeurer added a commit to asmeurer/PuDB that referenced this issue Mar 12, 2013
This (partially) fixes inducer#42, and also improves work on inducer#31.

Now, interrupting with Control-C works when the debugging is started with
set_trace().

The SIGINT handler is enabled via the public function
pudb.set_interrupt_handler.  If you want to be able to enter PuDB from within
your application, just call this function.  By default, it uses SIGINT (i.e.,
Control-C), but you can change it to use a different signal if that one
interferes.

There is still one major issue, which is that when you break in the middle of
an atomic operation, it goes to bdb. After pressing `n` several times you get
to your code, though.
asmeurer added a commit to asmeurer/PuDB that referenced this issue Mar 12, 2013
This (partially) fixes inducer#31, and also improves work on inducer#42.

Now, interrupting with Control-C works when the debugging is started with
set_trace().

The SIGINT handler is enabled via the public function
pudb.set_interrupt_handler.  If you want to be able to enter PuDB from within
your application, just call this function.  By default, it uses SIGINT (i.e.,
Control-C), but you can change it to use a different signal if that one
interferes.

There is still one major issue, which is that when you break in the middle of
an atomic operation, it goes to bdb. After pressing `n` several times you get
to your code, though.
@asmeurer
Copy link
Collaborator

See #63 for work on this. @stenyak and @mazubieta, does the API I have implemented there seem reasonable to you? If you could test it, that would be great too.

@inducer
Copy link
Owner

inducer commented Mar 12, 2013

What @asmeurer has implemented is (IMO) as good as it's going to get. Injecting debugger code into an already running Python process without its cooperation is a system-dependent nightmare that I'd prefer not to get into. Perhaps the only valid use case I can imagine is where you might have a daemon that runs without a console and you might still want to debug that. But you can get around that by running the daemon attached to a tmux and then using Aaron's signal-to-interrupt work.

So I'm not sure it's really a pressing issue that warrants all the effort. Closing as WONTFIX for now. If somebody comes up with something maintainable that works across Linux, Mac, (and perhaps Windows,) I might change my mind.

@inducer inducer closed this as completed Mar 12, 2013
asmeurer added a commit that referenced this issue Mar 12, 2013
Start fixing issue #42 and hopefully #31.
@asmeurer
Copy link
Collaborator

There's also one drawback, which is that if you use subprocesses or threads, you have to setup the handler in the main thread (see http://docs.python.org/2/library/signal.html#signal.signal). I'll add a note to the documentation.

@asmeurer
Copy link
Collaborator

Actually, I'm not even sure if it works at all if you use subprocesses. But that's a tricky debug situation anyway.

@seltzered
Copy link

seltzered commented Jul 7, 2023

I've been briefly looking at projects like madbg which uses pyinjector (both by @kmaork ) to inject a library into a running process to do debugging using ipython.

Is it possible to use these tools in a way to debug a running process with pudb? Is there something in pudb (API, args, etc.) that may need to be added to support this?

Enjoyed using pudb over the years and been curious if there's a way to keep using it for debugging running python processes.

@inducer
Copy link
Owner

inducer commented Jul 7, 2023

Thanks for the pointer. That looks like an interesting project.

@kmaork
Copy link

kmaork commented Jul 7, 2023

Would be glad to assist with adding this feature. Note that there's a new WIP version (kmaork/madbg#44) with many important improvements and a redesign, also adding support for multithreaded debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants