LLVM IR有调试器吗?

24

我想逐步分析一下我生成的LLVM IR代码。 就llc和lli而言,代码在语法和类型上是有效的,但结果并不是我所期望的。

由于代码块足够大,我无法轻松地找到错误,并且我很难制作一个具有相同错误的较小示例。

我想使用类似调试器的东西来调试LLVM IR。换句话说,我希望能够逐步执行llvm代码,检查“无限”寄存器(给定LLVM IR文件中的名称)和内存位置,设置断点,直到找到我的代码出了问题的地方。

我研究了llilldb,但都不是我要找的工具。lli将运行我的代码,但不能让我逐步执行。lldb似乎假设代码是由C前端生成的。

我对lldblli有误解吗? 有人知道是否有任何工具能满足我50%的要求吗?


1
作为一个猜测 - 你可以调试 lli 并查看它如何解释每个指令。不过,你需要进行一些黑客攻击来设置断点。 - arrowd
4个回答

13

我不知道这样的东西是否存在(我怀疑不存在),但我很乐意分享一下有关于llvm生成代码调试的观点。

  1. 调试生成的代码本身(在gdb中逐步执行)。
  2. 利用debugtrap内置函数(它只生成int3或者你所在架构上的等价物),你可以使用此函数来做断言并查看哪个断言失败。
  3. 给您的指令命名(使它们不再是%0%1,而是有意义的%names)-它们将出现在llc输出中作为注释。
  4. 为您的函数构建控制流图(CFG): opt --dot-cfg 1.ll; dot cfg.funcname.dot -Tpng > 1.png
  5. 不要忘记禁用LLVM优化(您可以使用后端-O3优化级别,但IR变换通道可能会使调试更加困难)。

因此,我建议的工作流程如下。建立CFG(第四步)和汇编语言(通过llc)。在gdb中停止到生成的代码处并逐步执行(或让其陷入其中一个断言)。将您在gdb中停止的地方与llc输出进行对应,阅读注释并将其与CFG进行关联。理解。

您还可以从生成的代码中构建CFG表示。在我所知道的工具中,IDA Pro(一种非常昂贵的构建CFG的方式)和Saga提供此类功能。

P.S.:最初这是一条评论,但它变得太长了。


8

以前有一个LLVM pass叫做-debug-ir可以实现这个功能。请参见this答案。

已经有尝试重新启用它,包括一个补丁

我需要这样的工具来调试我生成的一些代码。所以我将上面的补丁改编成了一个独立的工具,可以将行号信息附加到输入的LLVM-IR文件中,并产生一个输出的LLVM-IR,其调试信息引用输入文件。https://github.com/vaivaswatha/debugir


我使用了你的工具,但是它给了我一个错误提示:未定义命令:“-jit-kind”。请尝试“help”命令。 - ar2015
@ar2015,您尝试的gdb命令应该在开头加上set args。这是我的错误,我已经修复了。感谢您让我注意到它。 - Vaivaswatha N
非常感谢。现在很好了。这个库缺少的是如何使用输出代码中添加的符号的解释。我甚至不知道如何在gdb中打印变量%12,并使用debugir输出。 - ar2015
我在这里提出了一个问题:https://stackoverflow.com/q/67240807/4623526 - ar2015

2

我正在寻找同样的东西,我找到了这个:使用GDB调试JIT生成的代码

1)使用clang编译并发出字节码

clang++ -emit-llvm -D_GNU_SOURCE -D__STDC_LIMIT_MACROS -DDEBUG  -O0  -m64 -fomit-frame-pointer -c a.cpp -g -fno-use-cxa-atexit
clang++ -emit-llvm -D_GNU_SOURCE -D__STDC_LIMIT_MACROS -DDEBUG  -O0  -m64 -fomit-frame-pointer -c b.cpp -g -fno-use-cxa-atexit

2) 与llvm-link链接

llvm-link -o all.bc a.bc b.bc

3) 使用jit对代码进行调试,使用gdb和lli

gdb --quiet --args lli -jit-kind=mcjit all.bc


(gdb) b initCloneLookups
Function "initCloneLookups" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (initCloneLookups) pending.

(gdb) r
Starting program: lli -jit-kind=mcjit all.bc
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
......


Breakpoint 1, initCloneLookups () at a.cpp:66
66              clone_lookups = new BitBoard64[61];

在设置断点时输入 'y'。


2
请看这个工具,使用说明在这个补丁中。
该工具可以从您的LLVM IR文件生成另一个带有调试信息的LLVM IR文件,引用您的原始LLVM IR文件。您可以使用新的LLVM IR文件进行编译。在调试期间,您将处理原始LLVM IR文件的项目(堆栈跟踪、代码行)。
如果此回复对您有帮助,请为此回复点赞,以便其他人也知道如何调试LLVM IR文件,并在其上构建更多功能。目前看来,这是唯一可用的选项。
细节。
如果您需要处理裸的LLVM IR文件,例如手动编写的文件(与由其他语言的文件生成的编译器生成的LLVM IR文件相对应,例如C,其中生成的LLVM IR文件具有引用该C文件中代码行和符号的内联调试信息),
那么您可以使用上面提到的工具查看(崩溃)堆栈跟踪(LLVM IR函数),在您的LLVM IR函数上设置断点并使用调试器触发这些断点,可能会逐步执行您的LLVM IR代码(但我不确定能否查看变量、函数参数等的值)。

在应用此工具之前,最好将原始LLVM IR文件中所有出现的define internal 替换为define (删除函数定义的internal )。这样,调试器显示的堆栈跟踪将更加详细。

调试
上面提到的补丁提供了Mac OS上调试的详细信息。有关Win和Linux/WSL的信息,请参见下文。

在Windows中,我们使用了附带扩展CodeLLDB(v1.7.0)的Visual Studio Code。有关在VSCode中进行调试的更多详细信息。调试器配置文件示例“{Repo Root}/.vscode/launch.json”:
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "DebuggingLLVMIR", 
            "type": "lldb",
            "request": "launch",
            "cwd": "${workspaceFolder}\\some\\path", 
            "program": "${workspaceFolder}\\some\\path\\to\\your_exe.exe",
            "args": ["your_cmd_line_arg"],
            "environment": [
                { "name": "BUILD_CONFIGURATION", "value": "Debug" },  // Unrelated example of an env var.
                { "name": "PATH", "value": "../../SomeDir/bin/Debug/bin;../../../SomeDir/Native/build"}  // Optional.
            ],
            "console":"integratedTerminal"
        },
    ]
}

在Linux/WSL(Ubuntu 20.04)中有两个选项。
命令行LLDB。
lldb build/your_exe your_cmd_line_arg      # Launch the debugging session with LLDB debugger.
(lldb) r        # Run.
<Ctrl+c>        # Break.
(lldb) bt       # Stack Trace.
(lldb) f 1      # Select the stack trace frame 1.
(lldb) f 5      #                              5.
(lldb) q        # Quit the debugger.

使用 CodeLLDB(v1.7.0)扩展的 Visual Studio Code。
确保您可以在命令行中运行 ./build/your_exe your_cmd_line_arg。为此,您可能需要调整 LD_LIBRARY_PATH 环境变量。
export LD_LIBRARY_PATH=<absolute path to>/your/build:$LD_LIBRARY_PATH

# Make sure the var is set OK
env | grep LD_LIB

# Make sure all the dynamic lib paths are resolved correctly
ldd ./build/your_exe

# Make sure the executable runs
./build/your_exe your_cmd_line_arg

# Kill the run
<Ctrl+c>

现在启动VSCode。
调试器配置文件示例"{Repo Root}/.vscode/launch.json:":
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "DebuggingLLVMIR",
            "program": "${workspaceFolder}/path/to/your/build/your_exe",
            "args": ["your_cmd_line_arg"],
            "cwd": "${workspaceFolder}/path/to/your",
            //"environment": [
            //    { "name": "LD_LIBRARY_PATH", "value": "/mnt/c/path/to/your/build" },
            //    { "name": "PATH", "value": "/mnt/c/path/to/your/build"}
            //]
        }
    ]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接