| #!/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 <pid|processname> [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: Derive this differently to correctly support multi-arch. We could try to parse |
| # /proc/pid/exe. Right now, we prefer 64bit by checking those entries first. |
| # TODO: Correctly support native bridge, which makes parsing abilist very brittle. |
| # Note: Do NOT sort the entries alphabetically because of this. Fugu's abilist is |
| # "x86,armeabi-v7a,armeabi", and we need to grab the "x86". |
| # 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 =~ (^|,)x86_64 ]]; 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 =~ (^|,)x86 ]]; then # See note above for order. |
| GDB=x86_64-linux-android-gdb |
| elif [[ $CPU_ABI =~ (^|,)arm ]]; then |
| GDB=arm-linux-androideabi-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 $* |