[LLVMdev] Debugging LLVM IR with GDB

Will Dietz willdtz at gmail.com
Thu Oct 18 07:35:28 PDT 2012

On Thu, Oct 18, 2012 at 8:59 AM, Eli Bendersky <eliben at gmail.com> wrote:
>> Has anybody debugged LLVM IR with GDB? I'm using dragonegg to transform C
>> into IR, then applying my optimizations. Passing "-g" to dragonegg doesn't
>> seem to work since it generates debug info for the C code, not the IR. I
>> really need GDB (lli doesn't solve my problems) in order to debug
>> multi-threaded and multi-process MPI code.
>> More clearly, if I have a file hello.ll and I execute:
>> $> llc hello.ll -march=x86-64 -o hello.s
>> $> mpicc -O0 hello.s -o hello
>> Can I debug "hello" with GDB at the IR level? If so, how? If not, would it
>> be possible to add debug info generation at the IR level (and how much
>> effort required)? I read something about DwarfDebug but it's not clear to me
>> how to use it or even if it does what I need. I hope I didn't miss any
>> obvious solution.
> With the recent MCJIT work, C code compiled with LLVM can be debugged in GDB
> (http://llvm.org/docs/DebuggingJITedCode.html). Alas, this doesn't mean IR
> can be debugged as easily :-)
> The problem is the following: the debug information attached to each IR
> instruction by Clang refers to the original C code. When this debug info
> passes through the various layers of optimizations, MC, JITting, it remains
> pointing to C code. To debug IR, one would have to add debug info to each
> instruction, actually pointing to the IR itself. Then I guess GDB would know
> how to debug it, at least with a few tweaks, because GDB generally doesn't
> terribly care which language it debugs, as long as it can follow the debug
> info and the commands make sense (and this can be handled by adding
> appropriate Python plugins).
> Eli

Hi all,

For my own purposes, I wrote a pass that does exactly what you all are
describing: add debug metadata to LLVM IR.

As a pass, it had to tackle the problem of "This file needs to exist
on disk somewhere so gdb can find it", which I solved my dumping it
onto /tmp/ somewhere.  Not a great solution (who deletes these?) but
worked well enough.

Another interesting issue is how to coexist with any existing debug
metadata, which can be useful for simultaneously debugging an IR
transform inline with the C source for instrumentation-style passes
like SAFECode, ASan/TSan.

Quick Example:

(gdb) break main
Breakpoint 1 at 0x4010b1: file
/home/wdietz2/magic/test/unit/test_loop.c, line 9.
(gdb) r
Starting program:

Breakpoint 1, main (argc=<value optimized out>, argv=<value optimized
out>) at /home/wdietz2/magic/test/unit/test_loop.c:9
9         unsigned k = 0;
Missing separate debuginfos, use: debuginfo-install
glibc-2.12-1.80.el6_3.5.x86_64 libgcc-4.4.6-4.el6.x86_64
(gdb) n
10        source(argc != 0, &k);
(gdb) n
14        %and.i.i.i.i104 = and i64 %4, 70368744177660
(gdb) n
15        %5 = load i8** @global, align 8
(gdb) n
18        store i32 16843009, i32* %6, align 1
(gdb) n
19        store i8 1, i8* getelementptr inbounds ([1 x i8]* @array,
i64 0, i64 0), align 1
(gdb) n
20        call coldcc void @runtime_func() nounwind
(gdb) n
11        while(i-- > argc)
(gdb) n
23        %and.i.i.i.i85 = and i64 %7, 70368744177660
(gdb) n
14          while(j++ < i) k += j;
(gdb) n
11        while(i-- > argc)
(gdb) n
14          while(j++ < i) k += j;
(gdb) n
102       %77 = load i8** @global, align 8
(gdb) n
105       %79 = load i32* %78, align 4
(gdb) n
106       %cmp7.i.i.i = icmp ne i32 %79, 0
(gdb) n
108       call void @llvm.memset.p0i8.i64(i8* %add.ptr.i.i.i.i86, i8
%conv8.i.i.i, i64 4, i32 1, i1 false) nounwind
(gdb) n
14          while(j++ < i) k += j;
(gdb) n
15          while(j-- > 0) k *= k + j;
(gdb) n
95        %69 = load i8** @global, align 8
(gdb) n
98        %71 = load i32* %70, align 4

The pass itself is rather simple--the hard problem it solves is
emitting the IR to disk and reasoning about what Instruction* is on
what line, which really shouldn't be a problem if done properly in
LLVM.  If desired I can certainly make the code available on request.

In short, it seemed to work well for me and having it done properly in
LLVM itself would be great!


More information about the llvm-dev mailing list