Getting LLVM bitcode with Clang from Android

Posted on September 7, 2015 by Marko Dimjašević

Courtesy of johanferreira15

A few of us have been working on the CAVA project, which is short for Compositional Analysis of Android Bluetooth Software Stack. As you can imagine, the stack involves software written in multiple programming languages, e.g. Java, C, and C++. At the moment I’m focusing on the C/C++ part of the stack and we wanted to start playing with one of our C/C++ verifiers. As the verifiers are based on LLVM, my task was to compile the C/C++ part of the Bluetooth stack into the LLVM IR intermediate language, i.e. LLVM bitcode.

Courtesy of Google Inc.

Android, or the Android Open Source Project (AOSP) to be more precise, is freely available under the Apache 2.0 free software license. For one of my earlier projects I’d compiled instructions on how to obtain and build AOSP. By default, it is built with GCC. But, as I said before, I needed to get the LLVM bitcode out of it as well as a compiled version.

Compiling AOSP with LLVM’s Clang is fairly easy. Once you have the AOSP code base, open in an editor a file build/core/clear_vars.mk. It is a Makefile which sets and resets various variables used when building Android. As presented by Behan Webster, what suffices to do is to set the following initially unset variable:

LOCAL_CLANG:=true

This will make the build process use Clang instead of GCC’s g++, the GNU C++ compiler, when compiling Android. Just fire make in the root of the code base and that’s it.

It’s a bit tricky if you want to obtain LLVM bitcode as well. The main reason is that there is no build target that is for this, i.e for just emitting LLVM. I decided to have two separate things to achieve these two goals: 1) build and link Android as described above, 2) build Android up to the LLVM IR step into a separate output directory.

Luckily, the same clear_vars.mk file specifies a few other Clang variables, which should be set as follows:

LOCAL_CLANG_CFLAGS:=-emit-llvm -S
LOCAL_CLANG_CPPFLAGS:=-emit-llvm -S

Before running make again, for this goal you might want to have a different output directory. Therefore, run:

export OUT_DIR_COMMON_BASE=/path/to/another/dir
make --keep-going

The key argument to make is --keep-going, which will keep make going as far as possible after an error. Note that errors will occur because as mentioned before there is no target suitable for obtaining LLVM IR only. Therefore, this will get as much of your LLVM bitcode as possible, hopefully including parts you need.

Next, I am interested in Bluetooth only. In other words, preferably I want to compile a minimal chunk of Android that is enough to successfully build Bluetooth. After a while, I figured out there is a target called Bluetooth. Hence, with the goal of getting LLVM IR for Bluetooth and in particular the Bluetooth Java Native Interface, all one has to run with those variables in clear_vars.mk properly set is:

export OUT_DIR_COMMON_BASE=/path/to/another/dir
make --keep-going Bluetooth

The results will be in /path/to/another/dir. The JNI interface I am interested in is in this directory if built for x86:

/path/to/another/dir/target/product/generic_x86/
obj/SHARED_LIBRARIES/libbluetooth_jni_intermediates

From here I can move onto using the verifiers on this code base. I am hoping to report on that too.