Multithread C/C++ Debugging on Emulators and Rooted Devices from Android 1.5

In Android 2.2 Google announced ndk-gdb script which ease the debugging on the device. Later it turns out that it is not capable of debugging any other thread than the main thread.

In Android 2.3 Google ships fixed setup so you are now finally able to debug multithread application.

In fact multithread debugging is possible at least from Android 1.5. But you have to set up the environment yourself. Due to permissions limitation it is only possible on rooted devices. But it is possible on emulator as emulator is always rooted!

Here is a small shell script which does everything for you. It will start gdbserver on the device, gdb on PC and connect them together. It will also set up paths correctly so gdb can find its unstripped libraries on PC while having stripped libraries on the device.

Run this script from your project root directory. You have to modify APP_PACKAGE and ANDROID_TARGET variables to match your project settings. You also need to have you project compiled in debug mode. This can be done by running ndk-build NDK_DEBUG=1 or by setting android:debuggable=”true” in AndroidManifest.xml and compiling normally.

#!/bin/bash
# Martin Hejna (c) 2011
# martin.hejna@gmail.com
# CC-by


## Comment out for quiet run
set -x

# Set those variables to match your application
[ "$APP_PACKAGE" ] || APP_PACKAGE="com.example"
[ "$ANDROID_TARGET" ] || ANDROID_TARGET="android-9"

# Set installation paths of SDK and NDK
[ "$ANDROID_SDK" ] || ANDROID_SDK="/home/martin/Android/android-sdk-linux_86"
[ "$ANDROID_NDK" ] || ANDROID_NDK="/home/martin/Android/android-ndk-r5"

# adb and gdb executable paths
ADB="$ANDROID_SDK"/platform-tools/adb
GDB=$ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb

# Check we are in application root path (the one with AndroidManifest.xml in it)
APP_ROOT=`dirname $0`
if [ ! -f $APP_ROOT/AndroidManifest.xml ]
then
    echo This script must be run from package root directory
    echo This is the directory with AndroidManifest.xml in it
    exit 1
fi

# Path to unstripped versions of native .so libraries
UNSTRIPPED_SO_LIB="$APP_ROOT/obj/local/armeabi"
APP_PROCESS=$UNSTRIPPED_SO_LIB/app_process
APP_LIBC_SO=$UNSTRIPPED_SO_LIB/libc.so
if [ ! -d $UNSTRIPPED_SO_LIB ]; then
    echo Error: Directory $UNSTRIPPED_SO_LIB does not exist
    exit 1
fi

# Use cgdb if available
if which cgdb > /dev/null
then GDB_CMD="cgdb -d $GDB --"
else GDB_CMD=$GDB
fi

# We use same port number on pc and on device
DEBUG_PORT=5039

# File with gdb setup instructions (executed when gdb starts)
[ "$GDB_SETUP" ] || GDB_SETUP="/tmp/gdb.setup"


# Generate setup file for gdb with appropriate paths to symbols
function gdb_setup()
{
cat <<EOF >$GDB_SETUP
  set solib-search-path $UNSTRIPPED_SO_LIB:$ANDROID_NDK/platforms/$ANDROID_TARGET/arch-arm/usr/lib
  directory $ANDROID_NDK/platforms/$ANDROID_TARGET/arch-arm/usr/include $APP_ROOT/jni $ANDROID_NDK/sources/cxx-stl/system
  ## set solib-absolute-prefix $ANDROID_NDK/platforms/$ANDROID_TARGET/arch-arm/usr/lib

  file $APP_PROCESS
  target remote :$DEBUG_PORT

  # Probably not needed. Uncomment if you have problems with watchdogs
  ## set variable gDvm.nativeDebuggerActive=true
EOF
}

# Get pid of the process (first one if there are more of them)
function get_pid_on_device()
{
    $ADB shell ps | grep "$@" | awk '{print $2; exit}'
}


#############################################################################
## Main entry
############################################################################


# Restart adb server. Uncomment if you have problems with adb being stuck
## $ADB kill-server

# Get the app_process and libc.so from the device
# Always download and overwrite those files to be sure we have correct ones
$ADB pull /system/bin/app_process $APP_PROCESS
$ADB pull /system/lib/libc.so $APP_LIBC_SO

# Set up port forwarding for gdb and gdbserver
if $ADB forward tcp:$DEBUG_PORT tcp:$DEBUG_PORT
then :
else
    echo Failed to setup tcp forwarding for port $DEBUG_PORT
    echo Is the device running?
    exit 1
fi

# Get pid of the process
APP_PID=`get_pid_on_device "$APP_PACKAGE"`
if [ -z $APP_PID ]
then
    echo "$APP_PACKAGE is not running"
    exit 1
fi

# Kill any prior gdbserver
GDBSERV_PID=`get_pid_on_device gdbserver`
if [ -n "$GDBSERV_PID" ]
then 
    $ADB shell kill $GDBSERV_PID
    sleep 1
fi

# Start gdbserver and attach it to our application
$ADB shell gdbserver :$DEBUG_PORT --attach $APP_PID &
sleep 2

# Invoke gdb and feed it with setup commands to set up path to libraries
gdb_setup
$GDB_CMD -x $GDB_SETUP
rm -f $GDB_SETUP

Have fun!

About these ads
This entry was posted in Android and tagged , , , , . Bookmark the permalink.

4 Responses to Multithread C/C++ Debugging on Emulators and Rooted Devices from Android 1.5

  1. I’m now assured that i need to root my device. Thanks a lot for the remarkable suggestions

  2. Carlo Landry says:

    I am currently self-assured that i should root my cell phone. Thanks a lot for the fantastic tips

  3. Miller says:

    Does this work if I connect gdb from Eclipse? I used your previous post to connect gdb with Eclipse. It works on emulator but not on real device. Also, does this command script works on Windows? Maybe if I run it from Cygwin?

  4. Simpsonsss says:

    It is remarkable, very useful phrase
    Pavier Simpson
    I about it still heard nothing

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s