0

I want to send commands to a neovim instance from a lldb (gdb) extension python script. While this works without a problem with gdb, i get a python exception in lldb.

Minimal example:

(gdb) source test.py #works
(lldb) command script import test.py #raises an exception

test.py

import pynvim
pynvim.attach('socket', path='/tmp/nvimsocket')

exception:

error: module importing failed: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
  File "temp.py", line 1, in <module>                                          
  File "/opt/repos/nvim/test.py", line 5, in <module>    
    pynvim.attach('socket', path='/tmp/nvimsocket2') 
  File "/usr/lib/python3.8/site-packages/pynvim/__init__.py", line 122, in attach

    return Nvim.from_session(session).with_decode(decode)
  File "/usr/lib/python3.8/site-packages/pynvim/api/nvim.py", line 80, in from_session
    channel_id, metadata = session.request(b'nvim_get_api_info')
  File "/usr/lib/python3.8/site-packages/pynvim/msgpack_rpc/session.py", line 95, in request
    v = self._blocking_request(method, args)
  File "/usr/lib/python3.8/site-packages/pynvim/msgpack_rpc/session.py", line 174, in _blocking_request
    self._async_session.run(self._enqueue_request,
  File "/usr/lib/python3.8/site-packages/pynvim/msgpack_rpc/async_session.py", line 66, in run
    self._msgpack_stream.run(self._on_message)
  File "/usr/lib/python3.8/site-packages/pynvim/msgpack_rpc/msgpack_stream.py", line 43, in run
    self.loop.run(self._on_data)
  File "/usr/lib/python3.8/site-packages/pynvim/msgpack_rpc/event_loop/base.py", line 148, in run
    signal.signal(signal.SIGINT, default_int_handler)
  File "/usr/lib/python3.8/signal.py", line 47, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))

This seems to be an issue of the signal module an also affects other projects: https://github.com/python/asyncio/issues/396

It is possible to debug the python script that runs inside a virtual python env inside of lldb?

Edit:

If I try to import pdb and set a breakpoint with

pdb.set_trace()

(without the nvim stuff) this exception rises:

error: module importing failed: Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/test/python_debug/test.py", line 8, in <module>
    a()
  File "/home/test/python_debug/test.py", line 5, in a
    pdb.set_trace()
  File "/usr/lib/python3.8/pdb.py", line 1609, in set_trace
    pdb = Pdb()
  File "/usr/lib/python3.8/pdb.py", line 158, in __init__
    readline.set_completer_delims(' \t\n`@#$%^&*()=+[{]}\\|;:\'",<>?')
AttributeError: module 'lldb_editline' has no attribute 'set_completer_delims'

I built lldb from source, there are two flags:

LLDB_ENABLE_LIBEDIT
LLDB_ENABLE_CURSES

https://lldb.llvm.org/resources/build.html libedit is installed, how can I verify that it got activated? Is there something like lldb --build-flags ?

Amr Memdu
  • 41
  • 5

2 Answers2

1

You can use Python's pdb module to insert tracepoints in your test.py and lldb will stop in the pdb shell and allow you to step through the code. E.g.:

 > lldb
(lldb) platform shell cat /tmp/test.py
print("About to break")
import pdb
pdb.set_trace()
print("Back from break.")
(lldb) command script impo /tmp/test.py
About to break
> /tmp/test.py(4)<module>()
-> print("Back from break.")
(Pdb) n
Back from break.
--Return--
> /tmp/test.py(4)<module>()->None
-> print("Back from break.")
(Pdb) c
(lldb)
Jim Ingham
  • 25,260
  • 2
  • 55
  • 63
  • This also works for data formatters and breakpoint commands etc. Or at least it has for all the cases I've tried. – Jim Ingham Jan 15 '20 at 18:12
  • 1
    Unfortunately, I get another exception as soon as it hits set_trace(): AttributeError: module 'lldb_editline' has no attribute 'set_completer_delims. Maybe it has to do with the promt of pdb that isn't compatible with lldb's promt? Does your lldb have LLDB_ENABLE_LIBEDIT enabled/how can I check if mine has this flag activated? – Amr Memdu Jan 17 '20 at 05:47
  • Weird, I've never seen that. I don't ever build lldb without lib edit. You can tell experimentally: if you don't have lib edit then tab completion won't do anything. Can you try this also with an official build: one from Xcode if you are on macOS, and one of the releases for Linux if you are working there? It would be interesting to see if this is about your build or your platform's libedit? In any case this seems work a bug (http://bugs.llvm.org). – Jim Ingham Jan 17 '20 at 19:39
  • I'm on arch, tried both lldb from the repo as well as compiled it from source. libedit is enabled. I'll try with raspian now. – Amr Memdu Jan 18 '20 at 20:06
  • @AmrMemdu did you get rid of that error ? AttributeError: module 'lldb_editline' has no attribute 'set_completer_delims' – RichieHH Jun 30 '21 at 11:31
  • BTW I just compiled llvm from scratch with libedit enabled. linked against sys python 3.9.2 and still get the follwing when importing pdb and running setTrace or breakpoint() in my lldb python script : File "/usr/lib/python3.9/pdb.py", line 159, in __init__ readline.set_completer_delims(' \t\n`@#$%^&*()=+[{]}\\|;:\'",<>?') AttributeError: module 'lldb_editline' has no attribute 'set_completer_delims' – RichieHH Jun 30 '21 at 21:13
1

I had this same idea today! It seems that the lldb is changing the signal handler on you... you might want to try something like this:

import signal
from signal import default_int_handler
previous_handler = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, default_int_handler)    
import pynvim
pynvim.attach('socket', path='/tmp/nvimsocket')

to restore the handler to the correct value. However, this could mean that your signal handler for LLDB may no longer work. For some reason, if you try to restore it with previous_handler it may not work.

Noah
  • 13
  • 4