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
14echo
15
16function adb_get_product_device() {
17  local candidate=`adb shell getprop ro.hardware | tr -d '\r\n'`
18  if [[ "$candidate" =~ ^(goldfish|ranchu)$ ]]; then
19    # Emulator builds use product.device for OUT folder
20    candidate=`adb shell getprop ro.product.device | tr -d '\r\n'`
21  fi
22  echo $candidate
23}
24
25# returns 0 when process is not traced
26function adb_get_traced_by() {
27  echo `adb shell cat /proc/$1/status | grep -e "^TracerPid:" | sed "s/^TracerPid:\t//" | tr -d '\r\n'`
28}
29
30function get_symbols_directory()
31{
32    echo $(get_abs_build_var TARGET_OUT_UNSTRIPPED)
33}
34
35function gdbwrapper()
36{
37    local GDB_CMD="$1"
38    shift 1
39    $GDB_CMD -x "$@"
40}
41
42function gdbclient() {
43  local PROCESS_NAME="n/a"
44  local PID=$1
45  local PORT=5039
46  if [ -z "$PID" ]; then
47    echo "Usage: gdbclient <pid|processname> [port number]"
48    return -1
49  fi
50  local DEVICE=$(adb_get_product_device)
51
52  if [ -z "$DEVICE" ]; then
53    echo "Error: Unable to get device name. Please check if device is connected and ANDROID_SERIAL is set."
54    return -2
55  fi
56
57  if [ -n "$2" ]; then
58    PORT=$2
59  fi
60
61  local ROOT=$(gettop)
62  if [ -z "$ROOT" ]; then
63    # This is for the situation with downloaded symbols (from the build server)
64    # we check if they are available.
65    ROOT=`realpath .`
66  fi
67
68  local SYS_OUT_ROOT=$(get_build_var OUT_DIR)
69  local OUT_ROOT="${SYS_OUT_ROOT:-${OUT_DIR:-$ROOT/out}}/target/product/$DEVICE"
70  local SYMBOLS_DIR="$OUT_ROOT/symbols"
71  local IS_TAPAS_USER="$(get_build_var TARGET_BUILD_APPS)"
72  local TAPAS_SYMBOLS_DIR=
73
74  if [ $IS_TAPAS_USER ]; then
75    TAPAS_SYMBOLS_DIR=$(get_symbols_directory)
76  fi
77
78  if [ ! -d $SYMBOLS_DIR ]; then
79    if [ $IS_TAPAS_USER ]; then
80      mkdir -p $SYMBOLS_DIR/system/bin
81    else
82      echo "Error: couldn't find symbols: $SYMBOLS_DIR does not exist or is not a directory."
83      return -3
84    fi
85  fi
86
87  # let's figure out which executable we are about to debug
88
89  # check if user specified a name -> resolve to pid
90  if [[ ! "$PID" =~ ^[0-9]+$ ]] ; then
91    PROCESS_NAME=$PID
92    PID=$(pid --exact $PROCESS_NAME)
93    if [ -z "$PID" ]; then
94      echo "Error: couldn't resolve pid by process name: $PROCESS_NAME"
95      return -4
96    else
97      echo "Resolved pid for $PROCESS_NAME is $PID"
98    fi
99  fi
100
101  local ID=`adb shell id -u`
102  if [ "$ID" != "0" ]; then
103    echo "Error: gdbclient only works if you've run 'adb root'"
104    return -4
105  fi
106
107  local EXE=`adb shell readlink /proc/$PID/exe | tr -d '\r\n'`
108  if [ -z "$EXE" ]; then
109    echo "Error: couldn't find executable for pid $PID --- is the process still alive?"
110    return -4
111  fi
112
113  local LOCAL_EXE_PATH=$SYMBOLS_DIR$EXE
114
115  if [ ! -f $LOCAL_EXE_PATH ]; then
116    if [ $IS_TAPAS_USER ]; then
117      adb pull $EXE $LOCAL_EXE_PATH
118    else
119      echo "Error: unable to find symbols for executable $EXE: file $LOCAL_EXE_PATH does not exist"
120      return -5
121    fi
122  fi
123
124  local USE64BIT=""
125
126  if [[ "$(file $LOCAL_EXE_PATH)" =~ 64-bit ]]; then
127    USE64BIT="64"
128  fi
129
130  # and now linker for tapas users...
131  if [ -n "$IS_TAPAS_USER" -a ! -f "$SYMBOLS_DIR/system/bin/linker$USE64BIT" ]; then
132    adb pull /system/bin/linker$USE64BIT $SYMBOLS_DIR/system/bin/linker$USE64BIT
133  fi
134
135  local GDB
136  case $(uname -s) in
137    Darwin)
138      GDB=$ANDROID_BUILD_TOP/prebuilts/gdb/darwin-x86/bin/gdb
139      ;;
140
141    Linux)
142      GDB=$ANDROID_BUILD_TOP/prebuilts/gdb/linux-x86/bin/gdb
143      ;;
144
145    *)
146      echo "Error: Unknown platform '$(uname -s)'"
147      return 1
148      ;;
149  esac
150
151  local CPU_ABI=`adb shell getprop ro.product.cpu.abilist | tr -d '\r\n'`
152
153  # TODO: check if tracing process is gdbserver and not some random strace...
154  if [ "$(adb_get_traced_by $PID)" -eq 0 ]; then
155    # start gdbserver
156    echo "Starting gdbserver..."
157    # TODO: check if adb is already listening $PORT
158    # to avoid unnecessary calls
159    echo ". adb forward for port=$PORT..."
160    adb forward tcp:$PORT tcp:$PORT
161    echo ". starting gdbserver to attach to pid=$PID..."
162    adb shell gdbserver$USE64BIT :$PORT --attach $PID &
163    echo ". give it couple of seconds to start..."
164    sleep 2
165    echo ". done"
166  else
167    echo "It looks like gdbserver is already attached to $PID (process is traced), trying to connect to it using local port=$PORT"
168    adb forward tcp:$PORT tcp:$PORT
169  fi
170
171  local OUT_SO_SYMBOLS=$SYMBOLS_DIR/system/lib$USE64BIT
172  local TAPAS_OUT_SO_SYMBOLS=$TAPAS_SYMBOLS_DIR/system/lib$USE64BIT
173  local OUT_VENDOR_SO_SYMBOLS=$SYMBOLS_DIR/vendor/lib$USE64BIT
174  local ART_CMD=""
175
176  local SOLIB_SYSROOT=$SYMBOLS_DIR
177  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
178
179  if [ $IS_TAPAS_USER ]; then
180    SOLIB_SYSROOT=$TAPAS_SYMBOLS_DIR:$SOLIB_SYSROOT
181    SOLIB_SEARCHPATH=$TAPAS_OUT_SO_SYMBOLS:$SOLIB_SEARCHPATH
182  fi
183
184  echo >|"$OUT_ROOT/gdbclient.cmds" "set solib-absolute-prefix $SOLIB_SYSROOT"
185  echo >>"$OUT_ROOT/gdbclient.cmds" "set solib-search-path $SOLIB_SEARCHPATH"
186  local DALVIK_GDB_SCRIPT=$ROOT/development/scripts/gdb/dalvik.gdb
187  if [ -f $DALVIK_GDB_SCRIPT ]; then
188    echo >>"$OUT_ROOT/gdbclient.cmds" "source $DALVIK_GDB_SCRIPT"
189    ART_CMD="art-on"
190  else
191    echo "Warning: couldn't find $DALVIK_GDB_SCRIPT - ART debugging options will not be available"
192  fi
193  echo >>"$OUT_ROOT/gdbclient.cmds" "target remote :$PORT"
194  if [[ $EXE =~ (^|/)(app_process|dalvikvm)(|32|64)$ ]]; then
195    echo >> "$OUT_ROOT/gdbclient.cmds" $ART_CMD
196  fi
197
198  echo >>"$OUT_ROOT/gdbclient.cmds" ""
199
200  gdbwrapper $GDB "$OUT_ROOT/gdbclient.cmds" "$LOCAL_EXE_PATH"
201}
202
203gdbclient $*
204