4个版本

0.6.4 2024年5月22日
0.6.3 2024年5月12日
0.6.2 2024年5月12日
0.1.3 2023年10月3日

#1381过程宏


用于 chatdbg

Apache-2.0

14KB

ChatDBG

作者:Emery BergerStephen FreundKyla LevinNicolas van Kempen(按字母顺序排列)

PyPI Latest Release Downloads Downloads

ChatDBG是一个基于AI的调试助手,用于C/C++/Python/Rust代码,它将大型语言模型集成到标准调试器(pdblldbgdbwindbg)中,以帮助您调试代码。使用ChatDBG,您可以与调试器进行对话,对程序提出开放式问题,例如为什么x为null?。ChatDBG将接管调试器以回答您的查询。ChatDBG可以提供错误诊断和建议修复。

据我们所知,ChatDBG是第一个自动执行根本原因分析并提供建议修复的调试器。

观看ChatDBG的实际应用!

test-overflow.cpp 上的LLDB test-overflow.cpp 上的GDB bootstrap.py 上的Pdb

有关技术细节和完整评估,请参阅我们的arXiv论文,ChatDBG:人工智能调试助手PDF)。

[!注意]

ChatDBG支持pdblldbgdb,功能已完善;我们目前正在将这些调试器的功能移植到其他调试器。

安装

[!重要]

ChatDBG目前需要连接到OpenAI账户您的账户需要有正余额才能使用查看余额)。如果您从未购买过积分,您需要购买至少1美元的积分(如果您在2023年8月13日之前创建了API账户)或0.50美元(如果您有较新的API账户),以便访问ChatDBG使用的GPT-4。在此获取密钥。

一旦您有了API密钥,将其设置为名为OPENAI_API_KEY的环境变量。

export OPENAI_API_KEY=<your-api-key>

使用pip安装ChatDBG(如果您正在调试Python、C或C++代码,都需要这样做)

python3 -m pip install chatdbg

如果您使用ChatDBG调试Python程序,则已完成。如果您想使用ChatDBG通过gdblldb调试原生代码,请按照以下安装说明操作。

作为lldb扩展安装

lldb安装说明

通过运行以下命令将ChatDBG安装到lldb调试器中

Linux

python3 -m pip install ChatDBG
python3 -c 'import chatdbg; print(f"command script import {chatdbg.__path__[0]}/chatdbg_lldb.py")' >> ~/.lldbinit

如果您遇到错误,您可能正在使用较旧的LLVM版本。按照以下步骤更新到最新版本

sudo apt install -y lsb-release wget software-properties-common gnupg
curl -sSf https://apt.llvm.org/llvm.sh | sudo bash -s -- 18 all
# LLDB now available as `lldb-18`.

Mac

xcrun python3 -m pip install ChatDBG
xcrun python3 -c 'import chatdbg; print(f"command script import {chatdbg.__path__[0]}/chatdbg_lldb.py")' >> ~/.lldbinit

这将把ChatDBG作为LLVM扩展安装。

作为gdb扩展安装

gdb安装说明

通过运行以下命令将ChatDBG安装到gdb调试器中

python3 -m pip install ChatDBG
python3 -c 'import chatdbg; print(f"source {chatdbg.__path__[0]}/chatdbg_gdb.py")' >> ~/.gdbinit

这将把ChatDBG作为GDB扩展安装。

作为WinDBG扩展安装

WinDBG安装说明
  1. 安装WinDBG:如果尚未安装WinDBG,请按照此处的说明操作。
  2. 安装vcpkg:如果尚未安装vcpkg,请按照此处的说明操作。
  3. 安装Windows调试工具:从此处安装Windows SDK并勾选复选框Debugging Tools for Windows
  4. 导航到src\chatdbg目录cd src\chatdbg
  5. 安装所需依赖项:运行vcpkg install
  6. 构建chatdbg.dll扩展:运行mkdir build & cd build & cmake .. & cmake --build . & cd ..

使用ChatDBG:

  • 在WinDBGX中加载
    • 运行windbgx your_executable_here.exe
    • 点击菜单项查看 -> 命令浏览器
    • 在命令浏览器中输入.load debug\chatdbg.dll
  • 在运行代码并遇到异常/信号后
    • 在命令浏览器中输入!why

用法

调试Python

要使用ChatDBG调试Python程序,只需按照以下方式运行Python脚本

chatdbg -c continue yourscript.py

ChatDBG 是标准 Python 调试器 pdb 的扩展。与 pdb 类似,当您的脚本遇到未捕获的异常时,ChatDBG 将进入事后调试模式。

与其他调试器不同,您可以使用 why 命令来询问 ChatDBG 为什么您的程序失败,并获得建议的修复方案。在 LLM 响应后,您可以发出附加的调试命令或通过输入任何其他文本继续对话。

IPython 和 Jupyter 支持

要将 ChatDBG 作为 IPython 或 Jupyter Notebook 的默认调试器,请创建一个 IPython 配置文件,然后在启动时添加必要的扩展。(如果您已经有了自定义的配置文件,则需要根据需要修改这些行。)

ipython profile create
echo "c.InteractiveShellApp.extensions = ['chatdbg.chatdbg_pdb', 'ipyflow']" >> ~/.ipython/profile_default/ipython_config.py

在命令行中,您可以运行

ipython --pdb yourscript.py

在 Jupyter 中,使用 ipyflow 内核 运行您的笔记本,并在文件顶部包含此行魔法。

%pdb

调试原生代码(C、C++ 或 Rust)lldb / gdb)

要使用 ChatDBG 与 lldbgdb,只需用您的选择调试器运行原生代码(带有 -g 选项进行调试符号编译),当它崩溃时,询问 why。这也适用于事后调试(当您使用 -c 选项加载核心时)。

原生调试器的工作方式与 Pdb 略有不同。在调试器对您的提问做出响应后,您将进入 ChatDBG 的命令循环,如 (ChatDBG chatting) 提示所示。您可以继续发出调试命令,并且可以通过以 "chat" 开始的消息向 LLM 发送额外消息。完成时,键入 quit 返回到调试器的主命令循环。

调试 Rust 程序

要使用 ChatDBG 与 Rust,您需要执行两个步骤:修改您的 Cargo.toml 文件并在您的源程序中添加一行。

  1. 将此添加到您的 Cargo.toml 文件
[dependencies]
chatdbg = "0.6.2"

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
  1. 在您的程序中,将 #[chatdbg::main] 属性应用于 main 函数
#[chatdbg::main]
fn main() {

现在您可以使用 gdblldb 调试您的 Rust 代码。

示例

ChatDBG 示例在lldb
(ChatDBG lldb) run
Process 85494 launched: '/Users/emery/git/ChatDBG/test/a.out' (arm64)
TEST 1
TEST -422761288
TEST 0
TEST 0
TEST 0
TEST 0
TEST 0
TEST 0
Process 85494 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100056200)
    frame #0: 0x0000000100002f64 a.out`foo(n=8, b=1) at test.cpp:7:22
   4     int x[] = { 1, 2, 3, 4, 5 };
   5     
   6     void foo(int n, float b) {
-> 7       cout << "TEST " << x[n * 10000] << endl;
   8     }
   9     
   10    int main()
Target 0: (a.out) stopped.

询问 why 让 ChatDBG 提供一个有用的解释为什么这个程序失败,并建议一个修复方案

(ChatDBG lldb) why
The root cause of this error is accessing an index of the array `x`
that is out of bounds. In `foo()`, the index is calculated as `n *
10000`, which can be much larger than the size of the array `x` (which
is only 5 elements). In the given trace, the program is trying to
access the memory address `0x100056200`, which is outside of the range
of allocated memory for the array `x`.

To fix this error, we need to ensure that the index is within the
bounds of the array. One way to do this is to check the value of `n`
before calculating the index, and ensure that it is less than the size
of the array divided by the size of the element. For example, we can
modify `foo()` as follows:

    ```
    void foo(int n, float b) {
      if (n < 0 || n >= sizeof(x)/sizeof(x[0])) {
        cout << "ERROR: Invalid index" << endl;
        return;
      }
      cout << "TEST " << x[n] << endl;
    }
    ```

This code checks if `n` is within the valid range, and prints an error
message if it is not. If `n` is within the range, the function prints
the value of the element at index `n` of `x`. With this modification,
the program will avoid accessing memory outside the bounds of the
array, and will print the expected output for valid indices.
ChatDBG 示例在 Python(pdb)
Traceback (most recent call last):
  File "yourscript.py", line 9, in <module>
    print(tryme(100))
  File "yourscript.py", line 4, in tryme
    if x / i > 2:
ZeroDivisionError: division by zero
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> yourscript.py(4)tryme()
-> if x / i > 2:

询问 why 让 ChatDBG 提供一个有用的解释为什么这个程序失败,并建议一个修复方案

(ChatDBG Pdb) why
The root cause of the error is that the code is attempting to
divide by zero in the line "if x / i > 2". As i ranges from 0 to 99,
it will eventually reach the value of 0, causing a ZeroDivisionError.

A possible fix for this would be to add a check for i being equal to
zero before performing the division. This could be done by adding an
additional conditional statement, such as "if i == 0: continue", to
skip over the iteration when i is zero. The updated code would look
like this:

def tryme(x):
    count = 0
    for i in range(100):
        if i == 0:
            continue
        if x / i > 2:
            count += 1
    return count

if __name__ == '__main__':
    print(tryme(100))

依赖项

~260–700KB
~17K SLoC