如何在 gdb 中使用 IPython 交互式 shell? ||如何在 gdb 的 Python 交互式 (pi) shell 中使用制表符补全功能?

问题描述 投票:0回答:2

通常,在 Python shell 中,我可以按两次 Tab 键来获取提示列表。

另一方面,在 gdb 的 Python shell(

pi
python-interactive
命令)中,只有 gdb 风格的补全。

示例会话:

$ gdb -q
(gdb) pi
>>> gdb
<module 'gdb' from '/usr/share/gdb/python/gdb/__init__.py'>
>>> gdb.TabTab
... nothing ...
>>> show TabTab
Display all 148 possibilities? (y or n)
ada                              exec-direction                   record
agent                            exec-done-display                remote
annotate                         exec-file-mismatch               remoteaddresssize
[...]

Python 自动完成应该至少像这样。

$ python
Python 3.X.Y ...
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.TabTab
sys.abiflags                              sys.hash_info
sys.addaudithook(                         sys.hexversion
sys.api_version                           sys.implementation
[...]

如何在 gdb 中获得相同/相似的东西? 特别是具有制表符补全功能的 IPython shell 就很好。


失败的尝试:

  • 这个解决方案

    import readline
    import rlcompleter
    readline.parse_and_bind("tab: complete")
    
    当在

    sys. 或类似操作之后按下 Tab

     时,
    使 shell 输出文本制表符。

    至少它确实可以完成标识符选项卡(

    aTabTab
    )确实列出了一些条目)

    看起来这是因为与 gdb 的一些交互 -

    get_completer_delims
    每次都会重置为某个值,如果运行上面的代码,则制表符补全 outside gdb 也会切换到“Python 模式”。

  • 使用

    background_zmq_ipython
    会导致分段错误,因为某些gdb API(例如
    gdb.Value
    )无法从主线程外部读取。

  • 使用

    IPython.embed()
    还可以使 Tab 输出文字制表符。

  • 官方gdb文档https://sourceware.org/gdb/current/onlinedocs/gdb/Completion.html没有提及任何有关Python的内容。

python gdb
2个回答
3
投票

我想出了一些方法。

我不知道如何使用内置的

readline
库。 有关更多详细信息,请参阅问题中的失败尝试。


  1. 在调用

    IPython.embed
    之前重置 stdout 和 stderr。

    import sys
    sys.stdout=sys.__stdout__
    sys.stderr=sys.__stderr__
    
    import IPython
    IPython.embed(colors="neutral")
    

    记住之后重置 stdout 和 stderr 以避免可能的问题。

    参考:

    IPython 仅当 stdin、stdout 和 stderr 的 all 为 tty 设备时才使用制表符补全和颜色。 默认情况下,gdb sys.stdout 和 sys.stderr 是 gdb 包装器(以便 gdb 可以执行“按 Enter 继续” 当超过分页限制时)

  2. 启动一个内核,并单独启动一个控制台。

    import IPython
    IPython.embed_kernel()
    

    阅读控制台输出,了解如何连接以及如何从远程控制台退出终端。

    使用我的其他答案也可以通过编程方式远程退出终端。

  3. 启动内核(复杂的方式)

    阅读IPython源码,了解如何手动启动内核,并获取进程中的连接文件路径。

    import threading
    import subprocess
    import IPython
    from ipykernel.kernelapp import IPKernelApp
    import sys
    
    app = IPKernelApp.instance()
    app.initialize([])
    app.kernel.user_module = sys.modules[__name__]
    app.kernel.user_ns = locals()
    app.shell.set_completer_frame()
    
    def console_thread_run():
        subprocess.run(["jupyter-console", "--no-confirm-exit", "--existing", 
            app.abs_connection_file
            ])
        app.kernel.do_shutdown(restart=False)
    console_thread=threading.Thread(target=console_thread_run)
    console_thread.start()
    
    app.start()
    
  4. 使用

    background_zmq_ipython
    启动内核(访问内部属性,可能随时中断)。

    主要区别是

    sys.stdin
    sys.stdout
    等不受影响。参见
    background_zmq_ipython
    文档和 ipython - 为 Python 脚本提供远程 shell - Stack Overflow 了解更多详细信息。

    import subprocess
    import logging
    import threading
    
    from background_zmq_ipython import IPythonBackgroundKernelWrapper
    
    kernel_wrapper = IPythonBackgroundKernelWrapper(
            banner="", # default value is "Hello from background-zmq-ipython."
            user_ns=globals(),
            logger=logging.Logger("IPython", level=logging.INFO)
            # no handler
            # otherwise it will print "To connect another client to this IPython kernel" ...
            )
    kernel_wrapper.thread=threading.main_thread()  # workaround for assertions
    
    subprocess.Popen(["python", "-c",
        (
        "from jupyter_console.app import ZMQTerminalIPythonApp;"
        "app = ZMQTerminalIPythonApp();"
        "app.initialize();"
        "app.shell.own_kernel=True;"
        "app.start();"
        ),
        "--no-confirm-exit",
        "--existing", kernel_wrapper.connection_filename
        ])
    
    kernel_wrapper._thread_loop()
    

    还展示了如何将消息“保持内核活动”更改为“关闭内核”。


0
投票

所有方法对我来说都不是开箱即用的。

这就是我在 Debian 13 上的做法:

$ gdb
GNU gdb (Debian 13.1-3) 13.1 ...
(gdb) set $foo = 123
(gdb) print $foo
$1 = 123
(gdb) pi
>>> import IPython
>>> import sys
>>> sys.stderr=sys.__stderr__
>>> sys.stdout=sys.__stdout__
>>> IPython.embed_kernel()
0.00s - Debugger warning: It seems that frozen modules are being used, which may...

To connect another client to this kernel, use:
    --existing kernel-713400.json

在另一个外壳中:

$ jupyter console --existing kernel-713400.json
Jupyter console 6.4.4
Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0]
IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help.

# gdb.exec<TAB> - works
In [1]: gdb.execute("print $foo")
$2 = 123
© www.soinside.com 2019 - 2024. All rights reserved.