Home | History | Annotate | Download | only in scripts
      1 #!/bin/bash
      2 # TODO:
      3 # 1. Check for ANDROID_SERIAL/multiple devices
      4 
      5 if [ -z "$ANDROID_BUILD_TOP" ]; then
      6   >&2 echo '$ANDROID_BUILD_TOP is not set. Source build/envsetup.sh.'
      7   exit 1
      8 fi
      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.
     13 source $ANDROID_BUILD_TOP/build/envsetup.sh
     14 echo
     15 
     16 function 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
     26 function adb_get_traced_by() {
     27   echo `adb shell cat /proc/$1/status | grep -e "^TracerPid:" | sed "s/^TracerPid:[[:blank:]]//" | tr -d '\r\n'`
     28 }
     29 
     30 function get_symbols_directory()
     31 {
     32     echo $(get_abs_build_var TARGET_OUT_UNSTRIPPED)
     33 }
     34 
     35 function gdbwrapper()
     36 {
     37     local GDB_CMD="$1"
     38     shift 1
     39     $GDB_CMD -x "$@"
     40 }
     41 
     42 function 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 
    203 gdbclient $*
    204