1#!/bin/bash 2# TODO: 3# 1. Check for ANDROID_SERIAL/multiple devices 4 5if [ -z "$ANDROID_BUILD_TOP" ]; then 6 >&2 echo '$ANDROID_BUILD_TOP is not set. Source build/envsetup.sh.' 7 exit 1 8fi 9 10# We can use environment variables (like ANDROID_BUILD_TOP) from the user's 11# shell, but not functions (like gettop), so we need to source envsetup in here 12# as well. 13source $ANDROID_BUILD_TOP/build/envsetup.sh 14 15function adb_get_product_device() { 16 local candidate=`adb shell getprop ro.product.device | tr -d '\r\n'` 17 if [ -z $candidate ]; then 18 candidate=`adb shell getprop ro.hardware | tr -d '\r\n'` 19 fi 20 echo $candidate 21} 22 23# returns 0 when process is not traced 24function adb_get_traced_by() { 25 echo `adb shell cat /proc/$1/status | grep -e "^TracerPid:" | sed "s/^TracerPid:\t//" | tr -d '\r\n'` 26} 27 28function get_symbols_directory() 29{ 30 echo $(get_abs_build_var TARGET_OUT_UNSTRIPPED) 31} 32 33function gdbwrapper() 34{ 35 local GDB_CMD="$1" 36 shift 1 37 $GDB_CMD -x "$@" 38} 39 40function gdbclient() { 41 local PROCESS_NAME="n/a" 42 local PID=$1 43 local PORT=5039 44 if [ -z "$PID" ]; then 45 echo "Usage: gdbclient <pid|processname> [port number]" 46 return -1 47 fi 48 local DEVICE=$(adb_get_product_device) 49 50 if [ -z "$DEVICE" ]; then 51 echo "Error: Unable to get device name. Please check if device is connected and ANDROID_SERIAL is set." 52 return -2 53 fi 54 55 if [ -n "$2" ]; then 56 PORT=$2 57 fi 58 59 local ROOT=$(gettop) 60 if [ -z "$ROOT" ]; then 61 # This is for the situation with downloaded symbols (from the build server) 62 # we check if they are available. 63 ROOT=`realpath .` 64 fi 65 66 local OUT_ROOT="$ROOT/out/target/product/$DEVICE" 67 local SYMBOLS_DIR="$OUT_ROOT/symbols" 68 local IS_TAPAS_USER="$(get_build_var TARGET_BUILD_APPS)" 69 local TAPAS_SYMBOLS_DIR= 70 71 if [ $IS_TAPAS_USER ]; then 72 TAPAS_SYMBOLS_DIR=$(get_symbols_directory) 73 fi 74 75 if [ ! -d $SYMBOLS_DIR ]; then 76 if [ $IS_TAPAS_USER ]; then 77 mkdir -p $SYMBOLS_DIR/system/bin 78 else 79 echo "Error: couldn't find symbols: $SYMBOLS_DIR does not exist or is not a directory." 80 return -3 81 fi 82 fi 83 84 # let's figure out which executable we are about to debug 85 86 # check if user specified a name -> resolve to pid 87 if [[ ! "$PID" =~ ^[0-9]+$ ]] ; then 88 PROCESS_NAME=$PID 89 PID=$(pid --exact $PROCESS_NAME) 90 if [ -z "$PID" ]; then 91 echo "Error: couldn't resolve pid by process name: $PROCESS_NAME" 92 return -4 93 else 94 echo "Resolved pid for $PROCESS_NAME is $PID" 95 fi 96 fi 97 98 local EXE=`adb shell readlink /proc/$PID/exe | tr -d '\r\n'` 99 100 if [ -z "$EXE" ]; then 101 echo "Error: no such pid=$PID - is process still alive?" 102 return -4 103 fi 104 105 local LOCAL_EXE_PATH=$SYMBOLS_DIR$EXE 106 107 if [ ! -f $LOCAL_EXE_PATH ]; then 108 if [ $IS_TAPAS_USER ]; then 109 adb pull $EXE $LOCAL_EXE_PATH 110 else 111 echo "Error: unable to find symbols for executable $EXE: file $LOCAL_EXE_PATH does not exist" 112 return -5 113 fi 114 fi 115 116 local USE64BIT="" 117 118 if [[ "$(file $LOCAL_EXE_PATH)" =~ 64-bit ]]; then 119 USE64BIT="64" 120 fi 121 122 # and now linker for tapas users... 123 if [ -n "$IS_TAPAS_USER" -a ! -f "$SYMBOLS_DIR/system/bin/linker$USE64BIT" ]; then 124 adb pull /system/bin/linker$USE64BIT $SYMBOLS_DIR/system/bin/linker$USE64BIT 125 fi 126 127 local GDB= 128 local GDB64= 129 local CPU_ABI=`adb shell getprop ro.product.cpu.abilist | tr -d '\r\n'` 130 # TODO: Derive this differently to correctly support multi-arch. We could try to parse 131 # /proc/pid/exe. Right now, we prefer 64bit by checking those entries first. 132 # TODO: Correctly support native bridge, which makes parsing abilist very brittle. 133 # Note: Do NOT sort the entries alphabetically because of this. Fugu's abilist is 134 # "x86,armeabi-v7a,armeabi", and we need to grab the "x86". 135 # TODO: we assume these are available via $PATH 136 if [[ $CPU_ABI =~ (^|,)arm64 ]]; then 137 GDB=arm-linux-androideabi-gdb 138 GDB64=aarch64-linux-android-gdb 139 elif [[ $CPU_ABI =~ (^|,)x86_64 ]]; then 140 GDB=x86_64-linux-android-gdb 141 elif [[ $CPU_ABI =~ (^|,)mips64 ]]; then 142 GDB=mipsel-linux-android-gdb 143 GDB64=mips64el-linux-android-gdb 144 elif [[ $CPU_ABI =~ (^|,)x86 ]]; then # See note above for order. 145 GDB=x86_64-linux-android-gdb 146 elif [[ $CPU_ABI =~ (^|,)arm ]]; then 147 GDB=arm-linux-androideabi-gdb 148 elif [[ $CPU_ABI =~ (^|,)mips ]]; then 149 GDB=mipsel-linux-android-gdb 150 else 151 echo "Error: unrecognized cpu.abilist: $CPU_ABI" 152 return -6 153 fi 154 155 # TODO: check if tracing process is gdbserver and not some random strace... 156 if [ "$(adb_get_traced_by $PID)" -eq 0 ]; then 157 # start gdbserver 158 echo "Starting gdbserver..." 159 # TODO: check if adb is already listening $PORT 160 # to avoid unnecessary calls 161 echo ". adb forward for port=$PORT..." 162 adb forward tcp:$PORT tcp:$PORT 163 echo ". starting gdbserver to attach to pid=$PID..." 164 adb shell gdbserver$USE64BIT :$PORT --attach $PID & 165 echo ". give it couple of seconds to start..." 166 sleep 2 167 echo ". done" 168 else 169 echo "It looks like gdbserver is already attached to $PID (process is traced), trying to connect to it using local port=$PORT" 170 adb forward tcp:$PORT tcp:$PORT 171 fi 172 173 local OUT_SO_SYMBOLS=$SYMBOLS_DIR/system/lib$USE64BIT 174 local TAPAS_OUT_SO_SYMBOLS=$TAPAS_SYMBOLS_DIR/system/lib$USE64BIT 175 local OUT_VENDOR_SO_SYMBOLS=$SYMBOLS_DIR/vendor/lib$USE64BIT 176 local ART_CMD="" 177 178 local SOLIB_SYSROOT=$SYMBOLS_DIR 179 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 180 181 if [ $IS_TAPAS_USER ]; then 182 SOLIB_SYSROOT=$TAPAS_SYMBOLS_DIR:$SOLIB_SYSROOT 183 SOLIB_SEARCHPATH=$TAPAS_OUT_SO_SYMBOLS:$SOLIB_SEARCHPATH 184 fi 185 186 echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $SOLIB_SYSROOT" 187 echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $SOLIB_SEARCHPATH" 188 local DALVIK_GDB_SCRIPT=$ROOT/development/scripts/gdb/dalvik.gdb 189 if [ -f $DALVIK_GDB_SCRIPT ]; then 190 echo >>"$OUT_ROOT/gdbclient.cmds" "source $DALVIK_GDB_SCRIPT" 191 ART_CMD="art-on" 192 else 193 echo "Warning: couldn't find $DALVIK_GDB_SCRIPT - ART debugging options will not be available" 194 fi 195 echo >>"$OUT_ROOT/gdbclient.cmds" "target remote :$PORT" 196 if [[ $EXE =~ (^|/)(app_process|dalvikvm)(|32|64)$ ]]; then 197 echo >> "$OUT_ROOT/gdbclient.cmds" $ART_CMD 198 fi 199 200 echo >>"$OUT_ROOT/gdbclient.cmds" "" 201 202 local WHICH_GDB=$GDB 203 204 if [ -n "$USE64BIT" -a -n "$GDB64" ]; then 205 WHICH_GDB=$GDB64 206 fi 207 208 gdbwrapper $WHICH_GDB "$OUT_ROOT/gdbclient.cmds" "$LOCAL_EXE_PATH" 209} 210 211gdbclient $* 212