Is there a debugger for LLVM IR?
Asked Answered
S

4

25

I would like to step through some LLVM IR code I have generated. The code is syntactically and type valid as far as the llc and lli are concerned, but the results are not what I expected.

The chunks are large enough that I have been unsuccessful in simply reading out the bug, and I am having a hard time producing a smaller example with the same bug.

I figured that I could use something like a debugger, but for LLVM IR. In other words, I want to be able to step through the llvm code, examine the "infinite" registers (given the names in the LLVM IR file)and memory locations, set breakpoints, until I find where my code went wrong.

I looked into lli and lldb, but neither seems to be the tool I am looking for. lli will run my code but not let me go step by step. lldb seems to assume the code was generated by C frontends.

Am I wrong about lldb and lli? Does anyone know of a tool that does even 50% of what I want?

Shevat answered 13/8, 2015 at 9:33 Comment(1)
As a wild guess - you can debug lli and look how it interprets every instrucion. You'd have to do some hacking to set a breakpoint, though.Adela
S
13

I am not aware of such a thing (I suspect it does not exist). Though I will gladly share my points on llvm produced code debugging.

  1. Debug the generated code itself (step though it in gdb).
  2. Make use of the debugtrap intrinsic (which simply generates int3 or whatever equivalent on your architecture). You can make assertions with this thing and see which of them fails.
  3. Give your instructions names (so they are not %0, %1 but meaningful %names) -- they appear as comments in llc output.
  4. Build a CFG (control flow graph) for your function: opt --dot-cfg 1.ll; dot cfg.funcname.dot -Tpng > 1.png
  5. Don't forget to disable llvm optimizations (you can have backend -O3 optimization level, but IR transformation passes can make it harder to debug).

So the workflow I am suggesting is as follows. Build a CFG (4.) and assembly (via llc). Break to the generated code in gdb and step through it (or let it trap on one of your asserions). Correlate the point at which you stopped in gdb to llc output, read the comment, corellate to the CFG. Grok.

You can also build CFG representation out of the generated code. Of the tools I know IDA Pro (a very expensive way to build CFGs) and Saga offer such functionality.

P.S.: This was initially a comment, but it grew too long.

Survival answered 14/8, 2015 at 12:53 Comment(0)
R
8

There used to be an LLVM pass -debug-ir to do that. See this answer.

There have been attempts to revive it, including a patch.

I needed a utility like this to debug some code that I was generating. So I adapted the patch above into a standalone tool that can attach line number info into an input LLVM-IR file and produce an output LLVM-IR whose debug info refers to the input file. https://github.com/vaivaswatha/debugir

Ricercar answered 7/7, 2020 at 11:5 Comment(4)
I used your tool and it gives me an error: Undefined command: "-jit-kind". Try "help".Softwood
@Softwood The gdb command you tried should have had set args at the beginning. It was a mistake on my part and I've fixed it now. Thanks for bringing it to my attention.Ricercar
Thanks a lot. now is good. what the library lacks is the explanation of how the symbols added in the output code can be used. I even do not know how to print variable %12 in gdb using debugir output.Softwood
I asked it as a question here: https://mcmap.net/q/539594/-gdb-display-llvm-ir-variables-fails/4623526Softwood
A
2

I am looking for the same thing, and I found this : Debugging JIT-ed Code With GDB.

1) compile with clang and emit bytecode

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) link with llvm-link

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

3) debug with gdb and lli, using jit

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];

Answer 'y' on set breakpoint.

Antacid answered 19/4, 2017 at 16:47 Comment(0)
I
2

See this tool, instructions in this patch.

The tool can generate from your LLVM IR file another LLVM IR file with added debugging info referring to your original LLVM IR file. You then can use that new LLVM IR file for compilation. And during the debugging you will be dealing with the items (stack trace, lines of code) of your original LLVM IR file.

If this reply helps then please up-vote for this reply such that the others know how to debug LLVM IR files too, and build more functionality on top of it. At the moment looks like this is the only option available.

Details.
If you need to deal with bare LLVM IR files, e.g. manually-written
(as opposed to those generated by the compilers from the files in other languages, e.g. C, where the generated LLVM IR files have the in-line debugging info referring to the lines of code and symbols in that C file),
then you can see the (crash) stack trace (of LLVM IR functions), set breakpoints on your LLVM IR functions and hit those breakpoints with the debugger, probably step through your LLVM IR code (but I'm not sure about seeing the values of variables, function parameters, etc.)
by using the tool mentioned above.

Before applying the tool you better replace in your original LLVM IR file all the occurrences of define internal with define (remove internal for function definitions). After this the stack trace shown by the debugger will be more informative.

Debugging
The patch mentioned above provides the details about debugging in Mac OS. For Win and Linux/WSL see below.

In Windows
We used the Visual Studio Code with the extension CodeLLDB (v1.7.0). More details about debugging in VSCode.
The debugger configuration file example "{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"
        },
    ]
}

In Linux/WSL (Ubuntu 20.04)
Two options here.

Command-line 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.

Visual Studio Code with the extension CodeLLDB (v1.7.0)

Make sure that you can run ./build/your_exe your_cmd_line_arg in command line. For that you will likely need to adjust the LD_LIBRARY_PATH env var.

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>

Now start the VSCode.
The debuger configuration file example "{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"}
            //]
        }
    ]
}
Idzik answered 26/5, 2022 at 21:15 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.