Skip to content

TracerGrind on Android

Michael Eder edited this page Apr 11, 2016 · 14 revisions

Compilation:

See also valgrind-3.11.0/README.android

To cross-compile TracerGrind for Android:
Install first the usual TracerGrind dependencies on the host.

Then:

wget 'http://valgrind.org/downloads/valgrind-3.11.0.tar.bz2'
tar xf valgrind-3.11.0.tar.bz2
cp -r tracergrind valgrind-3.11.0/
patch -p0 < valgrind-3.11.0.diff
cd valgrind-3.11.0/
./autogen.sh
export NDKROOT=/path/to/your/android-ndk-r??

For ARM/AArch32:

export AR=$NDKROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar
export LD=$NDKROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ld
export CC=$NDKROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc

CPPFLAGS="--sysroot=$NDKROOT/platforms/android-3/arch-arm" \
   CFLAGS="--sysroot=$NDKROOT/platforms/android-3/arch-arm" \
   ./configure --prefix=/data/local/Inst \
   --host=armv7-unknown-linux --target=armv7-unknown-linux \
   --with-tmpdir=/sdcard

For ARM64/AArch64:

export AR=$NDKROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar
export LD=$NDKROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ld
export CC=$NDKROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc

CPPFLAGS="--sysroot=$NDKROOT/platforms/android-21/arch-arm64" \
   CFLAGS="--sysroot=$NDKROOT/platforms/android-21/arch-arm64" \
   ./configure --prefix=/data/local/Inst \
   --host=aarch64-unknown-linux --target=aarch64-unknown-linux \
   --with-tmpdir=/sdcard

Then compiling:

make -j8
mkdir ../build
make install DESTDIR=$(pwd)/../build

This creates a ../build/data/local/Inst

Installation:

If you use Adb Insecure, installation in /data/local/Inst/ is as easy as

adb push ../build /

Usage on the target:

/data/local/Inst/bin/valgrind --kernel-variant=android-gpu-adreno3xx \
                              --trace-children=yes \
                              --tool=tracergrind \
                              --filter=0x100000-0x200000 \
                              --vex-iropt-register-updates=allregs-at-mem-access \
                              --output=/sdcard/foo.trace mybin

Then as usual, on the host:

adb pull /sdcard/foo.trace .
sqlitetrace foo.trace foo.sqlite
tracegraph&

Tested configurations:

  • ARM, NDK r10e, Android 4.4
  • AArch64, NDK r10e, Android 5.1.1
  • ARM, Nexus 6, NDK r11b, Android 6
  • ARM, Nexus 4, NDK r11c, Android 4.4.4
  • ARM, Galaxy Nexus, NDK r11c, Android 4.4.4 (Cyanogenmod 11)

Tracing Android applications:

This was tested on Nexus 6 with rooted Android 6 Stock ROM. This is heavily based on this Stackoverflow answer.

First, it is required to know the package name of the application. A list of all packages installed gives

pm list packages

It is important that the package name is <=26 characters long because "wrap.$PACKAGENAME" mustn't be longer than 31 characters (this is a limitation of the Android system, not of Valgrind or any other of our tools).

Next, put the following start script to /data/local/start_valgrind.sh:

#!/system/bin/sh

PACKAGE="foo.bar.baz"

# TracerGrind
VGPARAMS='--kernel-variant=android-gpu-adreno3xx --trace-children=yes --tool=tracergrind --filter=foo.so --vex-iropt-register-updates=allregs-at-mem-access --output=/sdcard/foo.trace'

export TMPDIR=/data/data/$PACKAGE

exec /data/local/Inst/bin/valgrind $VGPARAMS $*

Make sure the package name is correct. You may remove or modify the filter parameter to your needs. Also, make sure that the script is accessible and executable.

After that, tell Android to start the application with your custom valgrind script:

PACKAGE="foo.bar.baz"
setprop wrap.$PACKAGE "logwrapper /data/local/start_valgrind.sh"

After that, starting the app on the phone or via am should result in Valgrind output in logcat. The trace can be found in /sdcard/foo.trace and from there everything works as usual.

Troubleshooting:

  • If somethings crashing and your device is soft rebooting, try disabling SELinux via setenforce 0
  • Sometimes the first start of the app after setting the logwrapper does not happen through the logwrapper. Simply stop the app and try starting the app again.
  • If valgrind has problems with writing to /sdcard/, make sure the application requires the permission android.permission.WRITE_EXTERNAL_STORAGE. On Android >=6, make sure the permission is also granted. If you're not sure, go to Settings -> Apps -> your_app -> Permissions and enable it from there.
  • Valgrind reports a lot of unhandled instructions and the collected trace contains invalid messages of type some_number when converting it with texttrace/sqlittetrace: Currently there's no solution for this, see issue #6
  • Nothing's happening after starting the app: If you can't see anything from start_valgrind.sh in your logcat, it's very likely that your package name is either wrong in start_valgrind.sh and/or your logwrapper. If there is output from start_valgrind.sh, look for error messages and file a new issue.

TODO:

Investigate unhandled instruction errors from issue #6