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