Home | History | Annotate | Download | only in android
      1 #!/bin/bash
      2 #
      3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 #
      7 
      8 # A generic script used to attach to a running Chromium process and
      9 # debug it. Most users should not use this directly, but one of the
     10 # wrapper scripts like adb_gdb_content_shell
     11 #
     12 # Use --help to print full usage instructions.
     13 #
     14 
     15 PROGNAME=$(basename "$0")
     16 PROGDIR=$(dirname "$0")
     17 
     18 # Location of Chromium-top-level sources.
     19 CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null)
     20 
     21 # Location of Chromium out/ directory.
     22 if [ -z "$CHROMIUM_OUT_DIR" ]; then
     23   CHROMIUM_OUT_DIR=out
     24 fi
     25 
     26 TMPDIR=
     27 GDBSERVER_PIDFILE=
     28 TARGET_GDBSERVER=
     29 
     30 clean_exit () {
     31   if [ "$TMPDIR" ]; then
     32     GDBSERVER_PID=$(cat $GDBSERVER_PIDFILE 2>/dev/null)
     33     if [ "$GDBSERVER_PID" ]; then
     34       log "Killing background gdbserver process: $GDBSERVER_PID"
     35       kill -9 $GDBSERVER_PID >/dev/null 2>&1
     36     fi
     37     if [ "$TARGET_GDBSERVER" ]; then
     38       log "Removing target gdbserver binary: $TARGET_GDBSERVER."
     39       "$ADB" shell rm "$TARGET_GDBSERVER" >/dev/null 2>&1
     40     fi
     41     log "Cleaning up: $TMPDIR"
     42     rm -rf "$TMPDIR"
     43   fi
     44   trap "" EXIT
     45   exit $1
     46 }
     47 
     48 # Ensure clean exit on Ctrl-C or normal exit.
     49 trap "clean_exit 1" INT HUP QUIT TERM
     50 trap "clean_exit \$?" EXIT
     51 
     52 panic () {
     53   echo "ERROR: $@" >&2
     54   exit 1
     55 }
     56 
     57 fail_panic () {
     58   if [ $? != 0 ]; then panic "$@"; fi
     59 }
     60 
     61 log () {
     62   if [ "$VERBOSE" -gt 0 ]; then
     63     echo "$@"
     64   fi
     65 }
     66 
     67 DEFAULT_PULL_LIBS_DIR=/tmp/$USER-adb-gdb-libs
     68 
     69 # NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX
     70 # environment variables. This is only for cosmetic reasons, i.e. to
     71 # display proper
     72 
     73 # Allow wrapper scripts to set the default activity through
     74 # the ADB_GDB_ACTIVITY variable. Users are still able to change the
     75 # final activity name through --activity=<name> option.
     76 #
     77 # This is only for cosmetic reasons, i.e. to display the proper default
     78 # in the --help output.
     79 #
     80 DEFAULT_ACTIVITY=${ADB_GDB_ACTIVITY:-".Main"}
     81 
     82 # Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME
     83 PROGNAME=${ADB_GDB_PROGNAME:-$(basename "$0")}
     84 
     85 ACTIVITY=$DEFAULT_ACTIVITY
     86 ADB=
     87 ANNOTATE=
     88 # Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it.
     89 BUILDTYPE=
     90 FORCE=
     91 GDBEXEPOSTFIX=gdb
     92 GDBINIT=
     93 GDBSERVER=
     94 HELP=
     95 NDK_DIR=
     96 NO_PULL_LIBS=
     97 PACKAGE_NAME=
     98 PID=
     99 PROGRAM_NAME="activity"
    100 PULL_LIBS=
    101 PULL_LIBS_DIR=
    102 SANDBOXED=
    103 SANDBOXED_INDEX=
    104 START=
    105 SU_PREFIX=
    106 SYMBOL_DIR=
    107 TARGET_ARCH=
    108 TOOLCHAIN=
    109 VERBOSE=0
    110 
    111 for opt; do
    112   optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
    113   case $opt in
    114     --adb=*)
    115       ADB=$optarg
    116       ;;
    117     --activity=*)
    118       ACTIVITY=$optarg
    119       ;;
    120     --annotate=3)
    121       ANNOTATE=$optarg
    122       ;;
    123     --force)
    124       FORCE=true
    125       ;;
    126     --gdbserver=*)
    127       GDBSERVER=$optarg
    128       ;;
    129     --gdb=*)
    130       GDB=$optarg
    131       ;;
    132     --help|-h|-?)
    133       HELP=true
    134       ;;
    135     --ndk-dir=*)
    136       NDK_DIR=$optarg
    137       ;;
    138     --no-pull-libs)
    139       NO_PULL_LIBS=true
    140       ;;
    141     --package-name=*)
    142       PACKAGE_NAME=$optarg
    143       ;;
    144     --pid=*)
    145       PID=$optarg
    146       ;;
    147     --program-name=*)
    148       PROGRAM_NAME=$optarg
    149       ;;
    150     --pull-libs)
    151       PULL_LIBS=true
    152       ;;
    153     --pull-libs-dir=*)
    154       PULL_LIBS_DIR=$optarg
    155       ;;
    156     --sandboxed)
    157       SANDBOXED=true
    158       ;;
    159     --sandboxed=*)
    160       SANDBOXED=true
    161       SANDBOXED_INDEX=$optarg
    162       ;;
    163     --script=*)
    164       GDBINIT=$optarg
    165       ;;
    166     --start)
    167       START=true
    168       ;;
    169     --su-prefix=*)
    170       SU_PREFIX=$optarg
    171       ;;
    172     --symbol-dir=*)
    173       SYMBOL_DIR=$optarg
    174       ;;
    175     --out-dir=*)
    176       CHROMIUM_OUT_DIR=$optarg
    177       ;;
    178     --target-arch=*)
    179       TARGET_ARCH=$optarg
    180       ;;
    181     --toolchain=*)
    182       TOOLCHAIN=$optarg
    183       ;;
    184     --ui)
    185       GDBEXEPOSTFIX=gdbtui
    186       ;;
    187     --verbose)
    188       VERBOSE=$(( $VERBOSE + 1 ))
    189       ;;
    190     --debug)
    191       BUILDTYPE=Debug
    192       ;;
    193     --release)
    194       BUILDTYPE=Release
    195       ;;
    196     -*)
    197       panic "Unknown option $OPT, see --help." >&2
    198       ;;
    199     *)
    200       if [ "$PACKAGE_NAME" ]; then
    201         panic "You can only provide a single package name as argument!\
    202  See --help."
    203       fi
    204       PACKAGE_NAME=$opt
    205       ;;
    206   esac
    207 done
    208 
    209 print_help_options () {
    210   cat <<EOF
    211 EOF
    212 }
    213 
    214 if [ "$HELP" ]; then
    215   if [ "$ADB_GDB_PROGNAME" ]; then
    216     # Assume wrapper scripts all provide a default package name.
    217     cat <<EOF
    218 Usage: $PROGNAME [options]
    219 
    220 Attach gdb to a running Android $PROGRAM_NAME process.
    221 EOF
    222   else
    223     # Assume this is a direct call to adb_gdb
    224   cat <<EOF
    225 Usage: $PROGNAME [options] [<package-name>]
    226 
    227 Attach gdb to a running Android $PROGRAM_NAME process.
    228 
    229 If provided, <package-name> must be the name of the Android application's
    230 package name to be debugged. You can also use --package-name=<name> to
    231 specify it.
    232 EOF
    233   fi
    234 
    235   cat <<EOF
    236 
    237 This script is used to debug a running $PROGRAM_NAME process.
    238 This can be a regular Android application process, or a sandboxed
    239 service, if you use the --sandboxed or --sandboxed=<num> option.
    240 
    241 This script needs several things to work properly. It will try to pick
    242 them up automatically for you though:
    243 
    244    - target gdbserver binary
    245    - host gdb client (e.g. arm-linux-androideabi-gdb)
    246    - directory with symbolic version of $PROGRAM_NAME's shared libraries.
    247 
    248 You can also use --ndk-dir=<path> to specify an alternative NDK installation
    249 directory.
    250 
    251 The script tries to find the most recent version of the debug version of
    252 shared libraries under one of the following directories:
    253 
    254   \$CHROMIUM_SRC/<out>/Release/lib/           (used by Ninja builds)
    255   \$CHROMIUM_SRC/<out>/Debug/lib/             (used by Ninja builds)
    256   \$CHROMIUM_SRC/<out>/Release/lib.target/    (used by Make builds)
    257   \$CHROMIUM_SRC/<out>/Debug/lib.target/      (used by Make builds)
    258 
    259 Where <out> is 'out' by default, unless the --out=<name> option is used or
    260 the CHROMIUM_OUT_DIR environment variable is defined.
    261 
    262 You can restrict this search by using --release or --debug to specify the
    263 build type, or simply use --symbol-dir=<path> to specify the file manually.
    264 
    265 The script tries to extract the target architecture from your GYP_DEFINES,
    266 but if this fails, will default to 'arm'. Use --target-arch=<name> to force
    267 its value.
    268 
    269 Otherwise, the script will complain, but you can use the --gdbserver,
    270 --gdb and --symbol-lib options to specify everything manually.
    271 
    272 An alternative to --gdb=<file> is to use --toollchain=<path> to specify
    273 the path to the host target-specific cross-toolchain.
    274 
    275 You will also need the 'adb' tool in your path. Otherwise, use the --adb
    276 option. The script will complain if there is more than one device connected
    277 and ANDROID_SERIAL is not defined.
    278 
    279 The first time you use it on a device, the script will pull many system
    280 libraries required by the process into a temporary directory. This
    281 is done to strongly improve the debugging experience, like allowing
    282 readable thread stacks and more. The libraries are copied to the following
    283 directory by default:
    284 
    285   $DEFAULT_PULL_LIBS_DIR/
    286 
    287 But you can use the --pull-libs-dir=<path> option to specify an
    288 alternative. The script can detect when you change the connected device,
    289 and will re-pull the libraries only in this case. You can however force it
    290 with the --pull-libs option.
    291 
    292 Any local .gdbinit script will be ignored, but it is possible to pass a
    293 gdb command script with the --script=<file> option. Note that its commands
    294 will be passed to gdb after the remote connection and library symbol
    295 loading have completed.
    296 
    297 Valid options:
    298   --help|-h|-?          Print this message.
    299   --verbose             Increase verbosity.
    300 
    301   --sandboxed           Debug first sandboxed process we find.
    302   --sandboxed=<num>     Debug specific sandboxed process.
    303   --symbol-dir=<path>   Specify directory with symbol shared libraries.
    304   --out-dir=<path>      Specify the out directory.
    305   --package-name=<name> Specify package name (alternative to 1st argument).
    306   --program-name=<name> Specify program name (cosmetic only).
    307   --pid=<pid>           Specify application process pid.
    308   --force               Kill any previous debugging session, if any.
    309   --start               Start package's activity on device.
    310   --ui                  Use gdbtui instead of gdb
    311   --activity=<name>     Activity name for --start [$DEFAULT_ACTIVITY].
    312   --annotate=<num>      Enable gdb annotation.
    313   --script=<file>       Specify extra GDB init script.
    314 
    315   --gdbserver=<file>    Specify target gdbserver binary.
    316   --gdb=<file>          Specify host gdb client binary.
    317   --target-arch=<name>  Specify NDK target arch.
    318   --adb=<file>          Specify host ADB binary.
    319 
    320   --su-prefix=<prefix>  Prepend <prefix> to 'adb shell' commands that are
    321                         run by this script. This can be useful to use
    322                         the 'su' program on rooted production devices.
    323                         e.g. --su-prefix="su -c"
    324 
    325   --pull-libs           Force system libraries extraction.
    326   --no-pull-libs        Do not extract any system library.
    327   --libs-dir=<path>     Specify system libraries extraction directory.
    328 
    329   --debug               Use libraries under out/Debug.
    330   --release             Use libraries under out/Release.
    331 
    332 EOF
    333   exit 0
    334 fi
    335 
    336 if [ -z "$PACKAGE_NAME" ]; then
    337   panic "Please specify a package name on the command line. See --help."
    338 fi
    339 
    340 if [ -z "$NDK_DIR" ]; then
    341   ANDROID_NDK_ROOT=$(PYTHONPATH=build/android python -c \
    342 'from pylib.constants import ANDROID_NDK_ROOT; print ANDROID_NDK_ROOT,')
    343 else
    344   if [ ! -d "$NDK_DIR" ]; then
    345     panic "Invalid directory: $NDK_DIR"
    346   fi
    347   if [ ! -f "$NDK_DIR/ndk-build" ]; then
    348     panic "Not a valid NDK directory: $NDK_DIR"
    349   fi
    350   ANDROID_NDK_ROOT=$NDK_DIR
    351 fi
    352 
    353 if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then
    354   panic "Unknown --script file: $GDBINIT"
    355 fi
    356 
    357 # Find the target architecture from our $GYP_DEFINES
    358 # This returns an NDK-compatible architecture name.
    359 # out: NDK Architecture name, or empty string.
    360 get_gyp_target_arch () {
    361   local ARCH=$(echo $GYP_DEFINES | tr ' ' '\n' | grep '^target_arch=' |\
    362                cut -d= -f2)
    363   case $ARCH in
    364     ia32|i?86|x86) echo "x86";;
    365     mips|arm|arm64|x86_64) echo "$ARCH";;
    366     *) echo "";
    367   esac
    368 }
    369 
    370 if [ -z "$TARGET_ARCH" ]; then
    371   TARGET_ARCH=$(get_gyp_target_arch)
    372   if [ -z "$TARGET_ARCH" ]; then
    373     TARGET_ARCH=arm
    374   fi
    375 else
    376   # Nit: accept Chromium's 'ia32' as a valid target architecture. This
    377   # script prefers the NDK 'x86' name instead because it uses it to find
    378   # NDK-specific files (host gdb) with it.
    379   if [ "$TARGET_ARCH" = "ia32" ]; then
    380     TARGET_ARCH=x86
    381     log "Auto-config: --arch=$TARGET_ARCH  (equivalent to ia32)"
    382   fi
    383 fi
    384 
    385 # Detect the NDK system name, i.e. the name used to identify the host.
    386 # out: NDK system name (e.g. 'linux' or 'darwin')
    387 get_ndk_host_system () {
    388   local HOST_OS
    389   if [ -z "$NDK_HOST_SYSTEM" ]; then
    390     HOST_OS=$(uname -s)
    391     case $HOST_OS in
    392       Linux) NDK_HOST_SYSTEM=linux;;
    393       Darwin) NDK_HOST_SYSTEM=darwin;;
    394       *) panic "You can't run this script on this system: $HOST_OS";;
    395     esac
    396   fi
    397   echo "$NDK_HOST_SYSTEM"
    398 }
    399 
    400 # Detect the NDK host architecture name.
    401 # out: NDK arch name (e.g. 'x86' or 'x86_64')
    402 get_ndk_host_arch () {
    403   local HOST_ARCH HOST_OS
    404   if [ -z "$NDK_HOST_ARCH" ]; then
    405     HOST_OS=$(get_ndk_host_system)
    406     HOST_ARCH=$(uname -p)
    407     case $HOST_ARCH in
    408       i?86) NDK_HOST_ARCH=x86;;
    409       x86_64|amd64) NDK_HOST_ARCH=x86_64;;
    410       *) panic "You can't run this script on this host architecture: $HOST_ARCH";;
    411     esac
    412     # Darwin trick: "uname -p" always returns i386 on 64-bit installations.
    413     if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then
    414       # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts
    415       # implementations of the tool. See http://b.android.com/53769
    416       HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64")
    417       if [ "$HOST_64BITS" ]; then
    418         NDK_HOST_ARCH=x86_64
    419       fi
    420     fi
    421   fi
    422   echo "$NDK_HOST_ARCH"
    423 }
    424 
    425 # Convert an NDK architecture name into a GNU configure triplet.
    426 # $1: NDK architecture name (e.g. 'arm')
    427 # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi')
    428 get_arch_gnu_config () {
    429   case $1 in
    430     arm)
    431       echo "arm-linux-androideabi"
    432       ;;
    433     arm64)
    434       echo "aarch64-linux-android"
    435       ;;
    436     x86)
    437       echo "i686-linux-android"
    438       ;;
    439     x86_64)
    440       echo "x86_64-linux-android"
    441       ;;
    442     mips)
    443       echo "mipsel-linux-android"
    444       ;;
    445     *)
    446       echo "$ARCH-linux-android"
    447       ;;
    448   esac
    449 }
    450 
    451 # Convert an NDK architecture name into a toolchain name prefix
    452 # $1: NDK architecture name (e.g. 'arm')
    453 # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi')
    454 get_arch_toolchain_prefix () {
    455   # Return the configure triplet, except for x86!
    456   if [ "$1" = "x86" ]; then
    457     echo "$1"
    458   else
    459     get_arch_gnu_config $1
    460   fi
    461 }
    462 
    463 # Find a NDK toolchain prebuilt file or sub-directory.
    464 # This will probe the various arch-specific toolchain directories
    465 # in the NDK for the needed file.
    466 # $1: NDK install path
    467 # $2: NDK architecture name
    468 # $3: prebuilt sub-path to look for.
    469 # Out: file path, or empty if none is found.
    470 get_ndk_toolchain_prebuilt () {
    471   local NDK_DIR="${1%/}"
    472   local ARCH="$2"
    473   local SUBPATH="$3"
    474   local NAME="$(get_arch_toolchain_prefix $ARCH)"
    475   local FILE TARGET
    476   FILE=$NDK_DIR/toolchains/$NAME-4.8/prebuilt/$SUBPATH
    477   if [ ! -f "$FILE" ]; then
    478     FILE=$NDK_DIR/toolchains/$NAME-4.9/prebuilt/$SUBPATH
    479     if [ ! -f "$FILE" ]; then
    480       FILE=$NDK_DIR/toolchains/$NAME-4.6/prebuilt/$SUBPATH
    481       if [ ! -f "$FILE" ]; then
    482         FILE=
    483       fi
    484     fi
    485   fi
    486   echo "$FILE"
    487 }
    488 
    489 # Find the path to an NDK's toolchain full prefix for a given architecture
    490 # $1: NDK install path
    491 # $2: NDK target architecture name
    492 # Out: install path + binary prefix (e.g.
    493 #      ".../path/to/bin/arm-linux-androideabi-")
    494 get_ndk_toolchain_fullprefix () {
    495   local NDK_DIR="$1"
    496   local ARCH="$2"
    497   local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG
    498 
    499   # NOTE: This will need to be updated if the NDK changes the names or moves
    500   #        the location of its prebuilt toolchains.
    501   #
    502   GCC=
    503   HOST_OS=$(get_ndk_host_system)
    504   HOST_ARCH=$(get_ndk_host_arch)
    505   CONFIG=$(get_arch_gnu_config $ARCH)
    506   GCC=$(get_ndk_toolchain_prebuilt \
    507         "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc")
    508   if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then
    509     GCC=$(get_ndk_toolchain_prebuilt \
    510           "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc")
    511   fi
    512   if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then
    513     # Special case, the x86 toolchain used to be incorrectly
    514     # named i686-android-linux-gcc!
    515     GCC=$(get_ndk_toolchain_prebuilt \
    516           "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc")
    517   fi
    518   if [ -z "$GCC" ]; then
    519     panic "Cannot find Android NDK toolchain for '$ARCH' architecture. \
    520 Please verify your NDK installation!"
    521   fi
    522   echo "${GCC%%gcc}"
    523 }
    524 
    525 # $1: NDK install path
    526 # $2: target architecture.
    527 get_ndk_gdbserver () {
    528   local NDK_DIR="$1"
    529   local ARCH=$2
    530   local BINARY
    531 
    532   # The location has moved after NDK r8
    533   BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver
    534   if [ ! -f "$BINARY" ]; then
    535     BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver)
    536   fi
    537   echo "$BINARY"
    538 }
    539 
    540 # Check/probe the path to the Android toolchain installation. Always
    541 # use the NDK versions of gdb and gdbserver. They must match to avoid
    542 # issues when both binaries do not speak the same wire protocol.
    543 #
    544 if [ -z "$TOOLCHAIN" ]; then
    545   ANDROID_TOOLCHAIN=$(get_ndk_toolchain_fullprefix \
    546                       "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
    547   ANDROID_TOOLCHAIN=$(dirname "$ANDROID_TOOLCHAIN")
    548   log "Auto-config: --toolchain=$ANDROID_TOOLCHAIN"
    549 else
    550   # Be flexible, allow one to specify either the install path or the bin
    551   # sub-directory in --toolchain:
    552   #
    553   if [ -d "$TOOLCHAIN/bin" ]; then
    554     TOOLCHAIN=$TOOLCHAIN/bin
    555   fi
    556   ANDROID_TOOLCHAIN=$TOOLCHAIN
    557 fi
    558 
    559 # Cosmetic: Remove trailing directory separator.
    560 ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN%/}
    561 
    562 # Find host GDB client binary
    563 if [ -z "$GDB" ]; then
    564   GDB=$(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev/null | head -1)
    565   if [ -z "$GDB" ]; then
    566     panic "Can't find Android gdb client in your path, check your \
    567 --toolchain or --gdb path."
    568   fi
    569   log "Host gdb client: $GDB"
    570 fi
    571 
    572 # Find gdbserver binary, we will later push it to /data/local/tmp
    573 # This ensures that both gdbserver and $GDB talk the same binary protocol,
    574 # otherwise weird problems will appear.
    575 #
    576 if [ -z "$GDBSERVER" ]; then
    577   GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
    578   if [ -z "$GDBSERVER" ]; then
    579     panic "Can't find NDK gdbserver binary. use --gdbserver to specify \
    580 valid one!"
    581   fi
    582   log "Auto-config: --gdbserver=$GDBSERVER"
    583 fi
    584 
    585 
    586 
    587 # Check that ADB is in our path
    588 if [ -z "$ADB" ]; then
    589   ADB=$(which adb 2>/dev/null)
    590   if [ -z "$ADB" ]; then
    591     panic "Can't find 'adb' tool in your path. Install it or use \
    592 --adb=<file>"
    593   fi
    594   log "Auto-config: --adb=$ADB"
    595 fi
    596 
    597 # Check that it works minimally
    598 ADB_VERSION=$($ADB version 2>/dev/null)
    599 echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge"
    600 if [ $? != 0 ]; then
    601   panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
    602 different one: $ADB"
    603 fi
    604 
    605 # If there are more than one device connected, and ANDROID_SERIAL is not
    606 # defined, print an error message.
    607 NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l)
    608 if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then
    609   echo "ERROR: There is more than one Android device connected to ADB."
    610   echo "Please define ANDROID_SERIAL to specify which one to use."
    611   exit 1
    612 fi
    613 
    614 # A unique ID for this script's session. This needs to be the same in all
    615 # sub-shell commands we're going to launch, so take the PID of the launcher
    616 # process.
    617 TMP_ID=$$
    618 
    619 # Temporary directory, will get cleaned up on exit.
    620 TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID
    621 mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/*
    622 
    623 GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid
    624 
    625 # Run a command through adb shell, strip the extra \r from the output
    626 # and return the correct status code to detect failures. This assumes
    627 # that the adb shell command prints a final \n to stdout.
    628 # $1+: command to run
    629 # Out: command's stdout
    630 # Return: command's status
    631 # Note: the command's stderr is lost
    632 adb_shell () {
    633   local TMPOUT="$(mktemp)"
    634   local LASTLINE RET
    635   local ADB=${ADB:-adb}
    636 
    637   # The weird sed rule is to strip the final \r on each output line
    638   # Since 'adb shell' never returns the command's proper exit/status code,
    639   # we force it to print it as '%%<status>' in the temporary output file,
    640   # which we will later strip from it.
    641   $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \
    642       sed -e 's![[:cntrl:]]!!g' > $TMPOUT
    643   # Get last line in log, which contains the exit code from the command
    644   LASTLINE=$(sed -e '$!d' $TMPOUT)
    645   # Extract the status code from the end of the line, which must
    646   # be '%%<code>'.
    647   RET=$(echo "$LASTLINE" | \
    648     awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }')
    649   # Remove the status code from the last line. Note that this may result
    650   # in an empty line.
    651   LASTLINE=$(echo "$LASTLINE" | \
    652     awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }')
    653   # The output itself: all lines except the status code.
    654   sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE"
    655   # Remove temp file.
    656   rm -f $TMPOUT
    657   # Exit with the appropriate status.
    658   return $RET
    659 }
    660 
    661 # If --force is specified, try to kill any gdbserver process started by the
    662 # same user on the device. Normally, these are killed automatically by the
    663 # script on exit, but there are a few corner cases where this would still
    664 # be needed.
    665 if [ "$FORCE" ]; then
    666   GDBSERVER_PIDS=$(adb_shell ps | awk '$9 ~ /gdbserver/ { print $2; }')
    667   for GDB_PID in $GDBSERVER_PIDS; do
    668     log "Killing previous gdbserver (PID=$GDB_PID)"
    669     adb_shell kill -9 $GDB_PID
    670   done
    671 fi
    672 
    673 if [ "$START" ]; then
    674   log "Starting $PROGRAM_NAME on device."
    675   adb_shell am start -n $PACKAGE_NAME/$ACTIVITY 2>/dev/null
    676   adb_shell ps | grep -q $PACKAGE_NAME
    677   fail_panic "Could not start $PROGRAM_NAME on device. Are you sure the \
    678 package is installed?"
    679 fi
    680 
    681 # Return the timestamp of a given time, as number of seconds since epoch.
    682 # $1: file path
    683 # Out: file timestamp
    684 get_file_timestamp () {
    685   stat -c %Y "$1" 2>/dev/null
    686 }
    687 
    688 # Detect the build type and symbol directory. This is done by finding
    689 # the most recent sub-directory containing debug shared libraries under
    690 # $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/
    691 #
    692 # $1: $BUILDTYPE value, can be empty
    693 # Out: nothing, but this sets SYMBOL_DIR
    694 #
    695 detect_symbol_dir () {
    696   local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP
    697   # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while
    698   # Make places then under out/$BUILDTYPE/lib.target.
    699   if [ "$1" ]; then
    700     SUBDIRS="$1/lib $1/lib.target"
    701   else
    702     SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target"
    703   fi
    704   LIST=$TMPDIR/scan-subdirs-$$.txt
    705   printf "" > "$LIST"
    706   for SUBDIR in $SUBDIRS; do
    707     DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
    708     if [ -d "$DIR" ]; then
    709       # Ignore build directories that don't contain symbol versions
    710       # of the shared libraries.
    711       DIR_LIBS=$(ls "$DIR"/lib*.so 2>/dev/null)
    712       if [ -z "$DIR_LIBS" ]; then
    713         echo "No shared libs: $DIR"
    714         continue
    715       fi
    716       TSTAMP=$(get_file_timestamp "$DIR")
    717       printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
    718     fi
    719   done
    720   SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2)
    721   rm -f "$LIST"
    722 
    723   if [ -z "$SUBDIR" ]; then
    724     if [ -z "$1" ]; then
    725       panic "Could not find any build directory under \
    726 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!"
    727     else
    728       panic "Could not find any $1 directory under \
    729 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!"
    730     fi
    731   fi
    732 
    733   SYMBOL_DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
    734   log "Auto-config: --symbol-dir=$SYMBOL_DIR"
    735 }
    736 
    737 if [ -z "$SYMBOL_DIR" ]; then
    738   detect_symbol_dir "$BUILDTYPE"
    739 fi
    740 
    741 # Allow several concurrent debugging sessions
    742 TARGET_GDBSERVER=/data/local/tmp/gdbserver-adb-gdb-$TMP_ID
    743 
    744 # Return the build fingerprint contained in a build.prop file.
    745 # $1: path to build.prop file
    746 get_build_fingerprint_from () {
    747   cat "$1" | grep -e '^ro.build.fingerprint=' | cut -d= -f2
    748 }
    749 
    750 
    751 ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR
    752 PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
    753 
    754 HOST_FINGERPRINT=
    755 DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
    756 log "Device build fingerprint: $DEVICE_FINGERPRINT"
    757 
    758 # If --pull-libs-dir is not specified, and this is a platform build, look
    759 # if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/
    760 # directly, if the build fingerprint matches the device.
    761 if [ -z "$ORG_PULL_LIBS_DIR" -a \
    762      "$ANDROID_PRODUCT_OUT" -a \
    763      -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then
    764   ANDROID_FINGERPRINT=$(get_build_fingerprint_from \
    765                         "$ANDROID_PRODUCT_OUT"/system/build.prop)
    766   log "Android build fingerprint:  $ANDROID_FINGERPRINT"
    767   if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then
    768     log "Perfect match!"
    769     PULL_LIBS_DIR=$ANDROID_PRODUCT_OUT/symbols
    770     HOST_FINGERPRINT=$ANDROID_FINGERPRINT
    771     if [ "$PULL_LIBS" ]; then
    772       log "Ignoring --pull-libs since the device and platform build \
    773 fingerprints match."
    774       NO_PULL_LIBS=true
    775     fi
    776   fi
    777 fi
    778 
    779 # If neither --pull-libs an --no-pull-libs were specified, check the build
    780 # fingerprints of the device, and the cached system libraries on the host.
    781 #
    782 if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then
    783   if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then
    784     log "Auto-config: --pull-libs  (no cached libraries)"
    785     PULL_LIBS=true
    786   else
    787     HOST_FINGERPRINT=$(get_build_fingerprint_from "$PULL_LIBS_DIR/build.prop")
    788     log "Host build fingerprint:   $HOST_FINGERPRINT"
    789     if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
    790       log "Auto-config: --no-pull-libs (fingerprint match)"
    791       NO_PULL_LIBS=true
    792     else
    793       log "Auto-config: --pull-libs  (fingerprint mismatch)"
    794       PULL_LIBS=true
    795     fi
    796   fi
    797 fi
    798 
    799 # Extract the system libraries from the device if necessary.
    800 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
    801   echo "Extracting system libraries into: $PULL_LIBS_DIR"
    802 fi
    803 
    804 mkdir -p "$PULL_LIBS_DIR"
    805 fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR"
    806 
    807 # If requested, work for M-x gdb.  The gdb indirections make it
    808 # difficult to pass --annotate=3 to the gdb binary itself.
    809 GDB_ARGS=
    810 if [ "$ANNOTATE" ]; then
    811   GDB_ARGS=$GDB_ARGS" --annotate=$ANNOTATE"
    812 fi
    813 
    814 # Get the PID from the first argument or else find the PID of the
    815 # browser process.
    816 if [ -z "$PID" ]; then
    817   PROCESSNAME=$PACKAGE_NAME
    818   if [ "$SANDBOXED_INDEX" ]; then
    819     PROCESSNAME=$PROCESSNAME:sandboxed_process$SANDBOXED_INDEX
    820   elif [ "$SANDBOXED" ]; then
    821     PROCESSNAME=$PROCESSNAME:sandboxed_process
    822     PID=$(adb_shell ps | \
    823           awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
    824   fi
    825   if [ -z "$PID" ]; then
    826     PID=$(adb_shell ps | \
    827           awk '$9 == "'$PROCESSNAME'" { print $2; }' | head -1)
    828   fi
    829   if [ -z "$PID" ]; then
    830     if [ "$START" ]; then
    831       panic "Can't find application process PID, did it crash?"
    832     else
    833       panic "Can't find application process PID, are you sure it is \
    834 running? Try using --start."
    835     fi
    836   fi
    837   log "Found process PID: $PID"
    838 elif [ "$SANDBOXED" ]; then
    839   echo "WARNING: --sandboxed option ignored due to use of --pid."
    840 fi
    841 
    842 # Determine if 'adb shell' runs as root or not.
    843 # If so, we can launch gdbserver directly, otherwise, we have to
    844 # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable.
    845 #
    846 if [ "$SU_PREFIX" ]; then
    847   # Need to check that this works properly.
    848   SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log
    849   adb_shell $SU_PREFIX echo "foo" > $SU_PREFIX_TEST_LOG 2>&1
    850   if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then
    851     echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:"
    852     echo "$ adb shell $SU_PREFIX echo foo"
    853     cat $SU_PREFIX_TEST_LOG
    854     exit 1
    855   fi
    856   COMMAND_PREFIX="$SU_PREFIX"
    857 else
    858   SHELL_UID=$(adb shell cat /proc/self/status | \
    859               awk '$1 == "Uid:" { print $2; }')
    860   log "Shell UID: $SHELL_UID"
    861   if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
    862     COMMAND_PREFIX="run-as $PACKAGE_NAME"
    863   else
    864     COMMAND_PREFIX=
    865   fi
    866 fi
    867 log "Command prefix: '$COMMAND_PREFIX'"
    868 
    869 # Pull device's system libraries that are mapped by our process.
    870 # Pulling all system libraries is too long, so determine which ones
    871 # we need by looking at /proc/$PID/maps instead
    872 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
    873   echo "Extracting system libraries into: $PULL_LIBS_DIR"
    874   rm -f $PULL_LIBS_DIR/build.prop
    875   MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps)
    876   if [ $? != 0 ]; then
    877     echo "ERROR: Could not list process's memory mappings."
    878     if [ "$SU_PREFIX" ]; then
    879       panic "Are you sure your --su-prefix is correct?"
    880     else
    881       panic "Use --su-prefix if the application is not debuggable."
    882     fi
    883   fi
    884   SYSTEM_LIBS=$(echo "$MAPPINGS" | \
    885       awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u)
    886   for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do
    887     echo "Pulling from device: $SYSLIB"
    888     DST_FILE=$PULL_LIBS_DIR$SYSLIB
    889     DST_DIR=$(dirname "$DST_FILE")
    890     mkdir -p "$DST_DIR" && adb pull $SYSLIB "$DST_FILE" 2>/dev/null
    891     fail_panic "Could not pull $SYSLIB from device !?"
    892   done
    893   echo "Pulling device build.prop"
    894   adb pull /system/build.prop $PULL_LIBS_DIR/build.prop
    895   fail_panic "Could not pull device build.prop !?"
    896 fi
    897 
    898 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
    899 # so we can add them to solib-search-path later.
    900 SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
    901              grep -v "^$" | tr '\n' ':')
    902 
    903 # This is a re-implementation of gdbclient, where we use compatible
    904 # versions of gdbserver and $GDBNAME to ensure that everything works
    905 # properly.
    906 #
    907 
    908 # Push gdbserver to the device
    909 log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER"
    910 adb push $GDBSERVER $TARGET_GDBSERVER &>/dev/null
    911 fail_panic "Could not copy gdbserver to the device!"
    912 
    913 PORT=5039
    914 HOST_PORT=$PORT
    915 TARGET_PORT=$PORT
    916 
    917 # Select correct app_process for architecture.
    918 case $TARGET_ARCH in
    919       arm|x86|mips) GDBEXEC=app_process;;
    920       arm64|x86_64) GDBEXEC=app_process64;;
    921       *) fail_panic "Unknown app_process for architecture!";;
    922 esac
    923 
    924 # Detect AddressSanitizer setup on the device. In that case app_process is a
    925 # script, and the real executable is app_process.real.
    926 GDBEXEC_ASAN=app_process.real
    927 adb_shell ls /system/bin/$GDBEXEC_ASAN
    928 if [ $? == 0 ]; then
    929     GDBEXEC=$GDBEXEC_ASAN
    930 fi
    931 
    932 # Pull the app_process binary from the device.
    933 log "Pulling $GDBEXEC from device"
    934 adb pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null
    935 fail_panic "Could not retrieve $GDBEXEC from the device!"
    936 
    937 # Setup network redirection
    938 log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)"
    939 adb forward tcp:$HOST_PORT tcp:$TARGET_PORT
    940 fail_panic "Could not setup network redirection from \
    941 host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!"
    942 
    943 # Start gdbserver in the background
    944 # Note that using run-as requires the package to be debuggable.
    945 #
    946 # If not, this will fail horribly. The alternative is to run the
    947 # program as root, which requires of course root privileges.
    948 # Maybe we should add a --root option to enable this?
    949 #
    950 log "Starting gdbserver in the background:"
    951 GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log
    952 log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
    953 --attach $PID"
    954 ("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
    955  --attach $PID > $GDBSERVER_LOG 2>&1) &
    956 GDBSERVER_PID=$!
    957 echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE
    958 log "background job pid: $GDBSERVER_PID"
    959 
    960 # Check that it is still running after a few seconds. If not, this means we
    961 # could not properly attach to it
    962 sleep 2
    963 log "Job control: $(jobs -l)"
    964 STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }')
    965 if [ "$STATE" != "Running" ]; then
    966   echo "ERROR: GDBServer could not attach to PID $PID!"
    967   echo "Failure log (use --verbose for more information):"
    968   cat $GDBSERVER_LOG
    969   exit 1
    970 fi
    971 
    972 # Generate a file containing useful GDB initialization commands
    973 readonly COMMANDS=$TMPDIR/gdb.init
    974 log "Generating GDB initialization commands file: $COMMANDS"
    975 echo -n "" > $COMMANDS
    976 echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS
    977 echo "directory $CHROMIUM_SRC" >> $COMMANDS
    978 echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS
    979 echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \
    980     >> $COMMANDS
    981 echo "echo Attaching and reading symbols, this may take a while.." \
    982     >> $COMMANDS
    983 echo "target remote :$HOST_PORT" >> $COMMANDS
    984 
    985 if [ "$GDBINIT" ]; then
    986   cat "$GDBINIT" >> $COMMANDS
    987 fi
    988 
    989 if [ "$VERBOSE" -gt 0 ]; then
    990   echo "### START $COMMANDS"
    991   cat $COMMANDS
    992   echo "### END $COMMANDS"
    993 fi
    994 
    995 log "Launching gdb client: $GDB $GDB_ARGS -x $COMMANDS"
    996 $GDB $GDB_ARGS -x $COMMANDS &&
    997 rm -f "$GDBSERVER_PIDFILE"
    998