LLVM Debugging Tips and Tricks

2 篇文章 0 订阅

Back when I was working heavily with LLVM, I learned a bunch of little tricks that made my life so much easier. I meant to document them back when they were fresh in my mind, but didn't get around to it. Now recently I've been chatting with several colleagues at UW that are just getting started with LLVM, and thought I'd go back and put together a couple of the useful tricks I learned.

This also follows on the heels of Adrian's fantastic post on how to get up and running using LLVM for research (which I highly recommend to anyone who ever needs to "do stuff with programs"). Adrian covers all the basics of why LLVM, how to get started, and what some basic passes could look like. The tricks I'll lay out here have more to do with day-to-day debugging tasks.

Debugging with LLDB

Imagine we want to poke around with something in the middle of our custom pass, to inspect how the data structures look, or chase down some bug. LLDB (LLVM's version of GDB) is a fantastic tool for playing with live code. It uses LLVM's formidable JIT tooling to interpret and run arbitrary code you give it (much more robustly than GDB ever has for me). This is extremely powerful especially as you're learning the ins and outs of LLVM's massive codebase.

There's just a couple little tricks to getting LLDB to work nicely for us. First, we need to build with Debug symbols. The best way to do this is to tell CMake to enable Debug symbols. Because CMake is CMake, you need to actually blow away your existing build/ directory and re-configure to change this, this time adding the option -DCMAKE_BUILD_TYPE=Debug:

 $ cmake .. -DCMAKE_BUILD_TYPE=Debug

Aside: If you're worried about performance, you could instead use RelWithDebInfo — this is the setting I recommend for building the rest of LLVM because otherwise it's painfully slow — but for my own code I build with Debug while developing.

Let's say we want to play around with the FunctionPass from before and find out more about how Functions are structured. So we want to run our pass with LLDB and set a breakpoint in our code, let's say at line 20, inside our loop over basic blocks.

 

First, we need to find out how to launch Clang with the LLDB debugger. It turns out clang is actually just a driver which figures out how to launch the correct subprocess to do your compile for you. We can see the commands it invokes using clang -v:

 

So, now that we know the command (clang-3.6 -cc1 ...), we can run that with LLDB, then we want to set a breakpoint in Skeleton.cpp, line 17 and then we can run the program:

 

Notice how at first, it didn't know what were talking about with Skeleton.cpp since that module is dynamically loaded by clang later. However, as soon as it was loaded, lldb obediently set the breakpoint we asked for!

Almost everything in LLVM has a dump() method — definitely anything descending from Value, which includes InstructionBasicBlockFunction, and even metadata (MDNode). This is super handy to use in your passes to find out what's going on. 

Protip: LLVM's C++ magic allows you to use the << operator with anything that has this dump method, so we could have just as easily written errs() << "Basic block:\n" << bb << "\n"; above. However, in the debugger, we use dump() to print to the console.

Now we can poke around a bit with LLVM. In lldbe or p (for GDB compatibility) are just shortcuts for "evaluate expression".

 

Because lldb leverages LLVM's own awesome parsing and JIT'ing functionality, it's possible to do all kinds of exploratory computation from the lldb prompt. The only real limitation is that you must have #include'd the headers for things you wish to work with, otherwise it probably won't have the full definition of the classes.

Viewing graphs

Another handy tool LLVM provides is automatic DOT graph generation for various objects. For instance, you can print the complete control-flow-graph (CFG) for a function with Function::viewCFG(). This is explained more in the programmer's manual, specifically here.

I have it on good authority (thanks Thierry!) that on OSX, if you use Homebrew, you can just do brew install graphvizand that should install the necessary libraries and tools for LLVM to do its thing.

This works particularly well from within LLDB:

 

Function::viewCFG()

As with everything else in LLVM, the DOT graph printer is built to be extended, so you can define custom graphs for debugging your passes, or for visualizing the output of your tool. A good place to start looking is in the documentation for DefaultDOTGraphTraits.

Getting source/line info for instructions

Many times when working with LLVM IR, I've wanted to be able to map instructions back to the source code they came from. There are just a couple gotchas with mapping instructions back to their original source code file and line number, so I thought I'd spend a few sentences explaining them.

First, you need another header (this is it's location in my version of LLVM, but they seem to change these paths fairly often so YMMV):

 

Then you just need to get the metadata for the instruction and extract the location information:

 

Update: The way to get location information has become simpler in newer versions of LLVM:

 

If you go ahead and try this, odds are good your first run will look something like this:

 

The big gotcha with source code info is that you need to instruct Clang/LLVM to generate this metadata, which it only does if you've specified that you want "debug symbols" or "debug info" by passing the -g flag (if you're not already in the habit of just always passing this flag to gcc/clang, now's the time to start).

 

Note: Even after running with -g, some instructions still won't have source location metdata. That's because they don't meaningfully correspond to a line number. This is true for the alloca instructions inserted by the compiler for stack variables, and probably for any code you've generated yourself. Or for highly-optimized code. So don't fret if you see it — and don't count on them being available everywhere.

Much more detailed instructions for all of this can be found in the LLVM Source Level Debugging docs.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值