diff --git a/scripts/gdbclient b/scripts/gdbclient new file mode 100755 index 000000000..b6a74c20d --- /dev/null +++ b/scripts/gdbclient @@ -0,0 +1,206 @@ +#!/bin/bash +# TODO: +# 1. Check for ANDROID_SERIAL/multiple devices + +if [ -z "$ANDROID_BUILD_TOP" ]; then + >&2 echo '$ANDROID_BUILD_TOP is not set. Source build/envsetup.sh.' + exit 1 +fi + +# We can use environment variables (like ANDROID_BUILD_TOP) from the user's +# shell, but not functions (like gettop), so we need to source envsetup in here +# as well. +source $ANDROID_BUILD_TOP/build/envsetup.sh + +function adb_get_product_device() { + local candidate=`adb shell getprop ro.product.device | sed s/.$//` + if [ -z $candidate ]; then + candidate=`adb shell getprop ro.hardware | sed s/.$//` + fi + echo $candidate +} + +# returns 0 when process is not traced +function adb_get_traced_by() { + echo `adb shell cat /proc/$1/status | grep -e "^TracerPid:" | sed "s/^TracerPid:\t//" | sed s/.$//` +} + +function get_symbols_directory() +{ + echo $(get_abs_build_var TARGET_OUT_UNSTRIPPED) +} + +function gdbwrapper() +{ + local GDB_CMD="$1" + shift 1 + $GDB_CMD -x "$@" +} + +function gdbclient() { + local PROCESS_NAME="n/a" + local PID=$1 + local PORT=5039 + if [ -z "$PID" ]; then + echo "Usage: gdbclient [port number]" + return -1 + fi + local DEVICE=$(adb_get_product_device) + + if [ -z "$DEVICE" ]; then + echo "Error: Unable to get device name. Please check if device is connected and ANDROID_SERIAL is set." + return -2 + fi + + if [ -n "$2" ]; then + PORT=$2 + fi + + local ROOT=$(gettop) + if [ -z "$ROOT" ]; then + # This is for the situation with downloaded symbols (from the build server) + # we check if they are available. + ROOT=`realpath .` + fi + + local OUT_ROOT="$ROOT/out/target/product/$DEVICE" + local SYMBOLS_DIR="$OUT_ROOT/symbols" + local IS_TAPAS_USER="$(get_build_var TARGET_BUILD_APPS)" + local TAPAS_SYMBOLS_DIR= + + if [ $IS_TAPAS_USER ]; then + TAPAS_SYMBOLS_DIR=$(get_symbols_directory) + fi + + if [ ! -d $SYMBOLS_DIR ]; then + if [ $IS_TAPAS_USER ]; then + mkdir -p $SYMBOLS_DIR/system/bin + else + echo "Error: couldn't find symbols: $SYMBOLS_DIR does not exist or is not a directory." + return -3 + fi + fi + + # let's figure out which executable we are about to debug + + # check if user specified a name -> resolve to pid + if [[ ! "$PID" =~ ^[0-9]+$ ]] ; then + PROCESS_NAME=$PID + PID=$(pid --exact $PROCESS_NAME) + if [ -z "$PID" ]; then + echo "Error: couldn't resolve pid by process name: $PROCESS_NAME" + return -4 + else + echo "Resolved pid for $PROCESS_NAME is $PID" + fi + fi + + local EXE=`adb shell readlink /proc/$PID/exe | sed s/.$//` + + if [ -z "$EXE" ]; then + echo "Error: no such pid=$PID - is process still alive?" + return -4 + fi + + local LOCAL_EXE_PATH=$SYMBOLS_DIR$EXE + + if [ ! -f $LOCAL_EXE_PATH ]; then + if [ $IS_TAPAS_USER ]; then + adb pull $EXE $LOCAL_EXE_PATH + else + echo "Error: unable to find symbols for executable $EXE: file $LOCAL_EXE_PATH does not exist" + return -5 + fi + fi + + local USE64BIT="" + + if [[ "$(file $LOCAL_EXE_PATH)" =~ 64-bit ]]; then + USE64BIT="64" + fi + + # and now linker for tapas users... + if [ -n "$IS_TAPAS_USER" -a ! -f "$SYMBOLS_DIR/system/bin/linker$USE64BIT" ]; then + adb pull /system/bin/linker$USE64BIT $SYMBOLS_DIR/system/bin/linker$USE64BIT + fi + + local GDB= + local GDB64= + local CPU_ABI=`adb shell getprop ro.product.cpu.abilist | sed s/.$//` + # TODO: we assume these are available via $PATH + if [[ $CPU_ABI =~ (^|,)arm64 ]]; then + GDB=arm-linux-androideabi-gdb + GDB64=aarch64-linux-android-gdb + elif [[ $CPU_ABI =~ (^|,)arm ]]; then + GDB=arm-linux-androideabi-gdb + elif [[ $CPU_ABI =~ (^|,)x86_64 ]]; then + GDB=x86_64-linux-android-gdb + elif [[ $CPU_ABI =~ (^|,)x86 ]]; then + GDB=x86_64-linux-android-gdb + elif [[ $CPU_ABI =~ (^|,)mips64 ]]; then + GDB=mipsel-linux-android-gdb + GDB64=mips64el-linux-android-gdb + elif [[ $CPU_ABI =~ (^|,)mips ]]; then + GDB=mipsel-linux-android-gdb + else + echo "Error: unrecognized cpu.abilist: $CPU_ABI" + return -6 + fi + + # TODO: check if tracing process is gdbserver and not some random strace... + if [ "$(adb_get_traced_by $PID)" -eq 0 ]; then + # start gdbserver + echo "Starting gdbserver..." + # TODO: check if adb is already listening $PORT + # to avoid unnecessary calls + echo ". adb forward for port=$PORT..." + adb forward tcp:$PORT tcp:$PORT + echo ". starting gdbserver to attach to pid=$PID..." + adb shell gdbserver$USE64BIT :$PORT --attach $PID & + echo ". give it couple of seconds to start..." + sleep 2 + echo ". done" + else + echo "It looks like gdbserver is already attached to $PID (process is traced), trying to connect to it using local port=$PORT" + adb forward tcp:$PORT tcp:$PORT + fi + + local OUT_SO_SYMBOLS=$SYMBOLS_DIR/system/lib$USE64BIT + local TAPAS_OUT_SO_SYMBOLS=$TAPAS_SYMBOLS_DIR/system/lib$USE64BIT + local OUT_VENDOR_SO_SYMBOLS=$SYMBOLS_DIR/vendor/lib$USE64BIT + local ART_CMD="" + + local SOLIB_SYSROOT=$SYMBOLS_DIR + local SOLIB_SEARCHPATH=$OUT_SO_SYMBOLS:$OUT_SO_SYMBOLS/hw:$OUT_SO_SYMBOLS/ssl/engines:$OUT_SO_SYMBOLS/drm:$OUT_SO_SYMBOLS/egl:$OUT_SO_SYMBOLS/soundfx:$OUT_VENDOR_SO_SYMBOLS:$OUT_VENDOR_SO_SYMBOLS/hw:$OUT_VENDOR_SO_SYMBOLS/egl + + if [ $IS_TAPAS_USER ]; then + SOLIB_SYSROOT=$TAPAS_SYMBOLS_DIR:$SOLIB_SYSROOT + SOLIB_SEARCHPATH=$TAPAS_OUT_SO_SYMBOLS:$SOLIB_SEARCHPATH + fi + + echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $SOLIB_SYSROOT" + echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $SOLIB_SEARCHPATH" + local DALVIK_GDB_SCRIPT=$ROOT/development/scripts/gdb/dalvik.gdb + if [ -f $DALVIK_GDB_SCRIPT ]; then + echo >>"$OUT_ROOT/gdbclient.cmds" "source $DALVIK_GDB_SCRIPT" + ART_CMD="art-on" + else + echo "Warning: couldn't find $DALVIK_GDB_SCRIPT - ART debugging options will not be available" + fi + echo >>"$OUT_ROOT/gdbclient.cmds" "target remote :$PORT" + if [[ $EXE =~ (^|/)(app_process|dalvikvm)(|32|64)$ ]]; then + echo >> "$OUT_ROOT/gdbclient.cmds" $ART_CMD + fi + + echo >>"$OUT_ROOT/gdbclient.cmds" "" + + local WHICH_GDB=$GDB + + if [ -n "$USE64BIT" -a -n "$GDB64" ]; then + WHICH_GDB=$GDB64 + fi + + gdbwrapper $WHICH_GDB "$OUT_ROOT/gdbclient.cmds" "$LOCAL_EXE_PATH" +} + +gdbclient $*