Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / build / android / adb_gdb
blob3612f90991bd4c55a67fe092243c822829c8c053
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 PRIVILEGED=
101 PRIVILEGED_INDEX=
102 PROGRAM_NAME="activity"
103 PULL_LIBS=
104 PULL_LIBS_DIR=
105 SANDBOXED=
106 SANDBOXED_INDEX=
107 START=
108 SU_PREFIX=
109 SYMBOL_DIR=
110 TARGET_ARCH=
111 TOOLCHAIN=
112 VERBOSE=0
114 for opt; do
115 optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
116 case $opt in
117 --adb=*)
118 ADB=$optarg
120 --activity=*)
121 ACTIVITY=$optarg
123 --annotate=3)
124 ANNOTATE=$optarg
126 --force)
127 FORCE=true
129 --gdbserver=*)
130 GDBSERVER=$optarg
132 --gdb=*)
133 GDB=$optarg
135 --help|-h|-?)
136 HELP=true
138 --ndk-dir=*)
139 NDK_DIR=$optarg
141 --no-pull-libs)
142 NO_PULL_LIBS=true
144 --package-name=*)
145 PACKAGE_NAME=$optarg
147 --pid=*)
148 PID=$optarg
150 --privileged)
151 PRIVILEGED=true
153 --privileged=*)
154 PRIVILEGED=true
155 PRIVILEGED_INDEX=$optarg
157 --program-name=*)
158 PROGRAM_NAME=$optarg
160 --pull-libs)
161 PULL_LIBS=true
163 --pull-libs-dir=*)
164 PULL_LIBS_DIR=$optarg
166 --sandboxed)
167 SANDBOXED=true
169 --sandboxed=*)
170 SANDBOXED=true
171 SANDBOXED_INDEX=$optarg
173 --script=*)
174 GDBINIT=$optarg
176 --start)
177 START=true
179 --su-prefix=*)
180 SU_PREFIX=$optarg
182 --symbol-dir=*)
183 SYMBOL_DIR=$optarg
185 --out-dir=*)
186 CHROMIUM_OUT_DIR=$optarg
188 --target-arch=*)
189 TARGET_ARCH=$optarg
191 --toolchain=*)
192 TOOLCHAIN=$optarg
194 --ui)
195 GDBEXEPOSTFIX=gdbtui
197 --verbose)
198 VERBOSE=$(( $VERBOSE + 1 ))
200 --debug)
201 BUILDTYPE=Debug
203 --release)
204 BUILDTYPE=Release
207 panic "Unknown option $OPT, see --help." >&2
210 if [ "$PACKAGE_NAME" ]; then
211 panic "You can only provide a single package name as argument!\
212 See --help."
214 PACKAGE_NAME=$opt
216 esac
217 done
219 print_help_options () {
220 cat <<EOF
224 if [ "$HELP" ]; then
225 if [ "$ADB_GDB_PROGNAME" ]; then
226 # Assume wrapper scripts all provide a default package name.
227 cat <<EOF
228 Usage: $PROGNAME [options]
230 Attach gdb to a running Android $PROGRAM_NAME process.
232 else
233 # Assume this is a direct call to adb_gdb
234 cat <<EOF
235 Usage: $PROGNAME [options] [<package-name>]
237 Attach gdb to a running Android $PROGRAM_NAME process.
239 If provided, <package-name> must be the name of the Android application's
240 package name to be debugged. You can also use --package-name=<name> to
241 specify it.
245 cat <<EOF
247 This script is used to debug a running $PROGRAM_NAME process.
248 This can be a regular Android application process, sandboxed (if you use the
249 --sandboxed or --sandboxed=<num> option) or a privileged (--privileged or
250 --privileged=<num>) service.
252 This script needs several things to work properly. It will try to pick
253 them up automatically for you though:
255 - target gdbserver binary
256 - host gdb client (e.g. arm-linux-androideabi-gdb)
257 - directory with symbolic version of $PROGRAM_NAME's shared libraries.
259 You can also use --ndk-dir=<path> to specify an alternative NDK installation
260 directory.
262 The script tries to find the most recent version of the debug version of
263 shared libraries under one of the following directories:
265 \$CHROMIUM_SRC/<out>/Release/lib/ (used by Ninja builds)
266 \$CHROMIUM_SRC/<out>/Debug/lib/ (used by Ninja builds)
267 \$CHROMIUM_SRC/<out>/Release/lib.target/ (used by Make builds)
268 \$CHROMIUM_SRC/<out>/Debug/lib.target/ (used by Make builds)
270 Where <out> is 'out' by default, unless the --out=<name> option is used or
271 the CHROMIUM_OUT_DIR environment variable is defined.
273 You can restrict this search by using --release or --debug to specify the
274 build type, or simply use --symbol-dir=<path> to specify the file manually.
276 The script tries to extract the target architecture from your target device,
277 but if this fails, will default to 'arm'. Use --target-arch=<name> to force
278 its value.
280 Otherwise, the script will complain, but you can use the --gdbserver,
281 --gdb and --symbol-lib options to specify everything manually.
283 An alternative to --gdb=<file> is to use --toollchain=<path> to specify
284 the path to the host target-specific cross-toolchain.
286 You will also need the 'adb' tool in your path. Otherwise, use the --adb
287 option. The script will complain if there is more than one device connected
288 and ANDROID_SERIAL is not defined.
290 The first time you use it on a device, the script will pull many system
291 libraries required by the process into a temporary directory. This
292 is done to strongly improve the debugging experience, like allowing
293 readable thread stacks and more. The libraries are copied to the following
294 directory by default:
296 $DEFAULT_PULL_LIBS_DIR/
298 But you can use the --pull-libs-dir=<path> option to specify an
299 alternative. The script can detect when you change the connected device,
300 and will re-pull the libraries only in this case. You can however force it
301 with the --pull-libs option.
303 Any local .gdbinit script will be ignored, but it is possible to pass a
304 gdb command script with the --script=<file> option. Note that its commands
305 will be passed to gdb after the remote connection and library symbol
306 loading have completed.
308 Valid options:
309 --help|-h|-? Print this message.
310 --verbose Increase verbosity.
312 --sandboxed Debug first sandboxed process we find.
313 --sandboxed=<num> Debug specific sandboxed process.
314 --symbol-dir=<path> Specify directory with symbol shared libraries.
315 --out-dir=<path> Specify the out directory.
316 --package-name=<name> Specify package name (alternative to 1st argument).
317 --privileged Debug first privileged process we find.
318 --privileged=<num> Debug specific privileged process.
319 --program-name=<name> Specify program name (cosmetic only).
320 --pid=<pid> Specify application process pid.
321 --force Kill any previous debugging session, if any.
322 --start Start package's activity on device.
323 --ui Use gdbtui instead of gdb
324 --activity=<name> Activity name for --start [$DEFAULT_ACTIVITY].
325 --annotate=<num> Enable gdb annotation.
326 --script=<file> Specify extra GDB init script.
328 --gdbserver=<file> Specify target gdbserver binary.
329 --gdb=<file> Specify host gdb client binary.
330 --target-arch=<name> Specify NDK target arch.
331 --adb=<file> Specify host ADB binary.
333 --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are
334 run by this script. This can be useful to use
335 the 'su' program on rooted production devices.
336 e.g. --su-prefix="su -c"
338 --pull-libs Force system libraries extraction.
339 --no-pull-libs Do not extract any system library.
340 --libs-dir=<path> Specify system libraries extraction directory.
342 --debug Use libraries under out/Debug.
343 --release Use libraries under out/Release.
346 exit 0
349 if [ -z "$PACKAGE_NAME" ]; then
350 panic "Please specify a package name on the command line. See --help."
353 if [ -z "$NDK_DIR" ]; then
354 ANDROID_NDK_ROOT=$(PYTHONPATH=$CHROMIUM_SRC/build/android python -c \
355 'from pylib.constants import ANDROID_NDK_ROOT; print ANDROID_NDK_ROOT,')
356 else
357 if [ ! -d "$NDK_DIR" ]; then
358 panic "Invalid directory: $NDK_DIR"
360 if [ ! -f "$NDK_DIR/ndk-build" ]; then
361 panic "Not a valid NDK directory: $NDK_DIR"
363 ANDROID_NDK_ROOT=$NDK_DIR
366 if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then
367 panic "Unknown --script file: $GDBINIT"
370 # Check that ADB is in our path
371 if [ -z "$ADB" ]; then
372 ADB=$(which adb 2>/dev/null)
373 if [ -z "$ADB" ]; then
374 panic "Can't find 'adb' tool in your path. Install it or use \
375 --adb=<file>"
377 log "Auto-config: --adb=$ADB"
380 # Check that it works minimally
381 ADB_VERSION=$($ADB version 2>/dev/null)
382 echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge"
383 if [ $? != 0 ]; then
384 panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
385 different one: $ADB"
388 # If there are more than one device connected, and ANDROID_SERIAL is not
389 # defined, print an error message.
390 NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l)
391 if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then
392 echo "ERROR: There is more than one Android device connected to ADB."
393 echo "Please define ANDROID_SERIAL to specify which one to use."
394 exit 1
397 # Run a command through adb shell, strip the extra \r from the output
398 # and return the correct status code to detect failures. This assumes
399 # that the adb shell command prints a final \n to stdout.
400 # $1+: command to run
401 # Out: command's stdout
402 # Return: command's status
403 # Note: the command's stderr is lost
404 adb_shell () {
405 local TMPOUT="$(mktemp)"
406 local LASTLINE RET
407 local ADB=${ADB:-adb}
409 # The weird sed rule is to strip the final \r on each output line
410 # Since 'adb shell' never returns the command's proper exit/status code,
411 # we force it to print it as '%%<status>' in the temporary output file,
412 # which we will later strip from it.
413 $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \
414 sed -e 's![[:cntrl:]]!!g' > $TMPOUT
415 # Get last line in log, which contains the exit code from the command
416 LASTLINE=$(sed -e '$!d' $TMPOUT)
417 # Extract the status code from the end of the line, which must
418 # be '%%<code>'.
419 RET=$(echo "$LASTLINE" | \
420 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }')
421 # Remove the status code from the last line. Note that this may result
422 # in an empty line.
423 LASTLINE=$(echo "$LASTLINE" | \
424 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }')
425 # The output itself: all lines except the status code.
426 sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE"
427 # Remove temp file.
428 rm -f $TMPOUT
429 # Exit with the appropriate status.
430 return $RET
433 # Find the target architecture from the target device.
434 # This returns an NDK-compatible architecture name.
435 # out: NDK Architecture name, or empty string.
436 get_gyp_target_arch () {
437 local ARCH=$(adb_shell getprop ro.product.cpu.abi)
438 case $ARCH in
439 mips|x86|x86_64) echo "$ARCH";;
440 arm64*) echo "arm64";;
441 arm*) echo "arm";;
442 *) echo "";
443 esac
446 if [ -z "$TARGET_ARCH" ]; then
447 TARGET_ARCH=$(get_gyp_target_arch)
448 if [ -z "$TARGET_ARCH" ]; then
449 TARGET_ARCH=arm
451 else
452 # Nit: accept Chromium's 'ia32' as a valid target architecture. This
453 # script prefers the NDK 'x86' name instead because it uses it to find
454 # NDK-specific files (host gdb) with it.
455 if [ "$TARGET_ARCH" = "ia32" ]; then
456 TARGET_ARCH=x86
457 log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)"
461 # Detect the NDK system name, i.e. the name used to identify the host.
462 # out: NDK system name (e.g. 'linux' or 'darwin')
463 get_ndk_host_system () {
464 local HOST_OS
465 if [ -z "$NDK_HOST_SYSTEM" ]; then
466 HOST_OS=$(uname -s)
467 case $HOST_OS in
468 Linux) NDK_HOST_SYSTEM=linux;;
469 Darwin) NDK_HOST_SYSTEM=darwin;;
470 *) panic "You can't run this script on this system: $HOST_OS";;
471 esac
473 echo "$NDK_HOST_SYSTEM"
476 # Detect the NDK host architecture name.
477 # out: NDK arch name (e.g. 'x86' or 'x86_64')
478 get_ndk_host_arch () {
479 local HOST_ARCH HOST_OS
480 if [ -z "$NDK_HOST_ARCH" ]; then
481 HOST_OS=$(get_ndk_host_system)
482 HOST_ARCH=$(uname -p)
483 case $HOST_ARCH in
484 i?86) NDK_HOST_ARCH=x86;;
485 x86_64|amd64) NDK_HOST_ARCH=x86_64;;
486 *) panic "You can't run this script on this host architecture: $HOST_ARCH";;
487 esac
488 # Darwin trick: "uname -p" always returns i386 on 64-bit installations.
489 if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then
490 # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts
491 # implementations of the tool. See http://b.android.com/53769
492 HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64")
493 if [ "$HOST_64BITS" ]; then
494 NDK_HOST_ARCH=x86_64
498 echo "$NDK_HOST_ARCH"
501 # Convert an NDK architecture name into a GNU configure triplet.
502 # $1: NDK architecture name (e.g. 'arm')
503 # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi')
504 get_arch_gnu_config () {
505 case $1 in
506 arm)
507 echo "arm-linux-androideabi"
509 arm64)
510 echo "aarch64-linux-android"
512 x86)
513 echo "i686-linux-android"
515 x86_64)
516 echo "x86_64-linux-android"
518 mips)
519 echo "mipsel-linux-android"
522 echo "$ARCH-linux-android"
524 esac
527 # Convert an NDK architecture name into a toolchain name prefix
528 # $1: NDK architecture name (e.g. 'arm')
529 # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi')
530 get_arch_toolchain_prefix () {
531 # Return the configure triplet, except for x86!
532 if [ "$1" = "x86" ]; then
533 echo "$1"
534 else
535 get_arch_gnu_config $1
539 # Find a NDK toolchain prebuilt file or sub-directory.
540 # This will probe the various arch-specific toolchain directories
541 # in the NDK for the needed file.
542 # $1: NDK install path
543 # $2: NDK architecture name
544 # $3: prebuilt sub-path to look for.
545 # Out: file path, or empty if none is found.
546 get_ndk_toolchain_prebuilt () {
547 local NDK_DIR="${1%/}"
548 local ARCH="$2"
549 local SUBPATH="$3"
550 local NAME="$(get_arch_toolchain_prefix $ARCH)"
551 local FILE TARGET
552 FILE=$NDK_DIR/toolchains/$NAME-4.9/prebuilt/$SUBPATH
553 if [ ! -f "$FILE" ]; then
554 FILE=$NDK_DIR/toolchains/$NAME-4.8/prebuilt/$SUBPATH
555 if [ ! -f "$FILE" ]; then
556 FILE=
559 echo "$FILE"
562 # Find the path to an NDK's toolchain full prefix for a given architecture
563 # $1: NDK install path
564 # $2: NDK target architecture name
565 # Out: install path + binary prefix (e.g.
566 # ".../path/to/bin/arm-linux-androideabi-")
567 get_ndk_toolchain_fullprefix () {
568 local NDK_DIR="$1"
569 local ARCH="$2"
570 local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG
572 # NOTE: This will need to be updated if the NDK changes the names or moves
573 # the location of its prebuilt toolchains.
575 GCC=
576 HOST_OS=$(get_ndk_host_system)
577 HOST_ARCH=$(get_ndk_host_arch)
578 CONFIG=$(get_arch_gnu_config $ARCH)
579 GCC=$(get_ndk_toolchain_prebuilt \
580 "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc")
581 if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then
582 GCC=$(get_ndk_toolchain_prebuilt \
583 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc")
585 if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then
586 # Special case, the x86 toolchain used to be incorrectly
587 # named i686-android-linux-gcc!
588 GCC=$(get_ndk_toolchain_prebuilt \
589 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc")
591 if [ -z "$GCC" ]; then
592 panic "Cannot find Android NDK toolchain for '$ARCH' architecture. \
593 Please verify your NDK installation!"
595 echo "${GCC%%gcc}"
598 # $1: NDK install path
599 # $2: target architecture.
600 get_ndk_gdbserver () {
601 local NDK_DIR="$1"
602 local ARCH=$2
603 local BINARY
605 # The location has moved after NDK r8
606 BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver
607 if [ ! -f "$BINARY" ]; then
608 BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver)
610 echo "$BINARY"
613 # Check/probe the path to the Android toolchain installation. Always
614 # use the NDK versions of gdb and gdbserver. They must match to avoid
615 # issues when both binaries do not speak the same wire protocol.
617 if [ -z "$TOOLCHAIN" ]; then
618 ANDROID_TOOLCHAIN=$(get_ndk_toolchain_fullprefix \
619 "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
620 ANDROID_TOOLCHAIN=$(dirname "$ANDROID_TOOLCHAIN")
621 log "Auto-config: --toolchain=$ANDROID_TOOLCHAIN"
622 else
623 # Be flexible, allow one to specify either the install path or the bin
624 # sub-directory in --toolchain:
626 if [ -d "$TOOLCHAIN/bin" ]; then
627 TOOLCHAIN=$TOOLCHAIN/bin
629 ANDROID_TOOLCHAIN=$TOOLCHAIN
632 # Cosmetic: Remove trailing directory separator.
633 ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN%/}
635 # Find host GDB client binary
636 if [ -z "$GDB" ]; then
637 GDB=$(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev/null | head -1)
638 if [ -z "$GDB" ]; then
639 panic "Can't find Android gdb client in your path, check your \
640 --toolchain or --gdb path."
642 log "Host gdb client: $GDB"
645 # Find gdbserver binary, we will later push it to /data/local/tmp
646 # This ensures that both gdbserver and $GDB talk the same binary protocol,
647 # otherwise weird problems will appear.
649 if [ -z "$GDBSERVER" ]; then
650 GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
651 if [ -z "$GDBSERVER" ]; then
652 panic "Can't find NDK gdbserver binary. use --gdbserver to specify \
653 valid one!"
655 log "Auto-config: --gdbserver=$GDBSERVER"
658 # A unique ID for this script's session. This needs to be the same in all
659 # sub-shell commands we're going to launch, so take the PID of the launcher
660 # process.
661 TMP_ID=$$
663 # Temporary directory, will get cleaned up on exit.
664 TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID
665 mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/*
667 GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid
669 # If --force is specified, try to kill any gdbserver process started by the
670 # same user on the device. Normally, these are killed automatically by the
671 # script on exit, but there are a few corner cases where this would still
672 # be needed.
673 if [ "$FORCE" ]; then
674 GDBSERVER_PIDS=$(adb_shell ps | awk '$9 ~ /gdbserver/ { print $2; }')
675 for GDB_PID in $GDBSERVER_PIDS; do
676 log "Killing previous gdbserver (PID=$GDB_PID)"
677 adb_shell kill -9 $GDB_PID
678 done
681 if [ "$START" ]; then
682 log "Starting $PROGRAM_NAME on device."
683 adb_shell am start -n $PACKAGE_NAME/$ACTIVITY 2>/dev/null
684 adb_shell ps | grep -q $PACKAGE_NAME
685 fail_panic "Could not start $PROGRAM_NAME on device. Are you sure the \
686 package is installed?"
689 # Return the timestamp of a given time, as number of seconds since epoch.
690 # $1: file path
691 # Out: file timestamp
692 get_file_timestamp () {
693 stat -c %Y "$1" 2>/dev/null
696 # Detect the build type and symbol directory. This is done by finding
697 # the most recent sub-directory containing debug shared libraries under
698 # $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/
700 # $1: $BUILDTYPE value, can be empty
701 # Out: nothing, but this sets SYMBOL_DIR
703 detect_symbol_dir () {
704 local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP
705 # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while
706 # Make places then under out/$BUILDTYPE/lib.target.
707 if [ "$1" ]; then
708 SUBDIRS="$1/lib $1/lib.target"
709 else
710 SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target"
712 LIST=$TMPDIR/scan-subdirs-$$.txt
713 printf "" > "$LIST"
714 for SUBDIR in $SUBDIRS; do
715 DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
716 if [ -d "$DIR" ]; then
717 # Ignore build directories that don't contain symbol versions
718 # of the shared libraries.
719 DIR_LIBS=$(ls "$DIR"/lib*.so 2>/dev/null)
720 if [ -z "$DIR_LIBS" ]; then
721 echo "No shared libs: $DIR"
722 continue
724 TSTAMP=$(get_file_timestamp "$DIR")
725 printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
727 done
728 SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2)
729 rm -f "$LIST"
731 if [ -z "$SUBDIR" ]; then
732 if [ -z "$1" ]; then
733 panic "Could not find any build directory under \
734 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!"
735 else
736 panic "Could not find any $1 directory under \
737 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!"
741 SYMBOL_DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
742 log "Auto-config: --symbol-dir=$SYMBOL_DIR"
745 if [ -z "$SYMBOL_DIR" ]; then
746 detect_symbol_dir "$BUILDTYPE"
749 # Allow several concurrent debugging sessions
750 TARGET_GDBSERVER=/data/data/$PACKAGE_NAME/gdbserver-adb-gdb-$TMP_ID
751 TMP_TARGET_GDBSERVER=/data/local/tmp/gdbserver-adb-gdb-$TMP_ID
753 # Return the build fingerprint contained in a build.prop file.
754 # $1: path to build.prop file
755 get_build_fingerprint_from () {
756 cat "$1" | grep -e '^ro.build.fingerprint=' | cut -d= -f2
760 ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR
761 PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
763 HOST_FINGERPRINT=
764 DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
765 log "Device build fingerprint: $DEVICE_FINGERPRINT"
767 # If --pull-libs-dir is not specified, and this is a platform build, look
768 # if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/
769 # directly, if the build fingerprint matches the device.
770 if [ -z "$ORG_PULL_LIBS_DIR" -a \
771 "$ANDROID_PRODUCT_OUT" -a \
772 -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then
773 ANDROID_FINGERPRINT=$(get_build_fingerprint_from \
774 "$ANDROID_PRODUCT_OUT"/system/build.prop)
775 log "Android build fingerprint: $ANDROID_FINGERPRINT"
776 if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then
777 log "Perfect match!"
778 PULL_LIBS_DIR=$ANDROID_PRODUCT_OUT/symbols
779 HOST_FINGERPRINT=$ANDROID_FINGERPRINT
780 if [ "$PULL_LIBS" ]; then
781 log "Ignoring --pull-libs since the device and platform build \
782 fingerprints match."
783 NO_PULL_LIBS=true
788 # If neither --pull-libs an --no-pull-libs were specified, check the build
789 # fingerprints of the device, and the cached system libraries on the host.
791 if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then
792 if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then
793 log "Auto-config: --pull-libs (no cached libraries)"
794 PULL_LIBS=true
795 else
796 HOST_FINGERPRINT=$(get_build_fingerprint_from "$PULL_LIBS_DIR/build.prop")
797 log "Host build fingerprint: $HOST_FINGERPRINT"
798 if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
799 log "Auto-config: --no-pull-libs (fingerprint match)"
800 NO_PULL_LIBS=true
801 else
802 log "Auto-config: --pull-libs (fingerprint mismatch)"
803 PULL_LIBS=true
808 # Extract the system libraries from the device if necessary.
809 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
810 echo "Extracting system libraries into: $PULL_LIBS_DIR"
813 mkdir -p "$PULL_LIBS_DIR"
814 fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR"
816 # If requested, work for M-x gdb. The gdb indirections make it
817 # difficult to pass --annotate=3 to the gdb binary itself.
818 GDB_ARGS=
819 if [ "$ANNOTATE" ]; then
820 GDB_ARGS=$GDB_ARGS" --annotate=$ANNOTATE"
823 # Get the PID from the first argument or else find the PID of the
824 # browser process.
825 if [ -z "$PID" ]; then
826 PROCESSNAME=$PACKAGE_NAME
827 if [ "$SANDBOXED_INDEX" ]; then
828 PROCESSNAME=$PROCESSNAME:sandboxed_process$SANDBOXED_INDEX
829 elif [ "$SANDBOXED" ]; then
830 PROCESSNAME=$PROCESSNAME:sandboxed_process
831 PID=$(adb_shell ps | \
832 awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
833 elif [ "$PRIVILEGED_INDEX" ]; then
834 PROCESSNAME=$PROCESSNAME:privileged_process$PRIVILEGED_INDEX
835 elif [ "$PRIVILEGED" ]; then
836 PROCESSNAME=$PROCESSNAME:privileged_process
837 PID=$(adb_shell ps | \
838 awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
840 if [ -z "$PID" ]; then
841 PID=$(adb_shell ps | \
842 awk '$9 == "'$PROCESSNAME'" { print $2; }' | head -1)
844 if [ -z "$PID" ]; then
845 if [ "$START" ]; then
846 panic "Can't find application process PID, did it crash?"
847 else
848 panic "Can't find application process PID, are you sure it is \
849 running? Try using --start."
852 log "Found process PID: $PID"
853 elif [ "$SANDBOXED" ]; then
854 echo "WARNING: --sandboxed option ignored due to use of --pid."
855 elif [ "$PRIVILEGED" ]; then
856 echo "WARNING: --privileged option ignored due to use of --pid."
859 # Determine if 'adb shell' runs as root or not.
860 # If so, we can launch gdbserver directly, otherwise, we have to
861 # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable.
863 if [ "$SU_PREFIX" ]; then
864 # Need to check that this works properly.
865 SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log
866 adb_shell $SU_PREFIX \"echo "foo"\" > $SU_PREFIX_TEST_LOG 2>&1
867 if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then
868 echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:"
869 echo "$ adb shell $SU_PREFIX \"echo foo\""
870 cat $SU_PREFIX_TEST_LOG
871 exit 1
873 COMMAND_PREFIX="$SU_PREFIX \""
874 COMMAND_SUFFIX="\""
875 else
876 SHELL_UID=$(adb shell cat /proc/self/status | \
877 awk '$1 == "Uid:" { print $2; }')
878 log "Shell UID: $SHELL_UID"
879 if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
880 COMMAND_PREFIX="run-as $PACKAGE_NAME"
881 COMMAND_SUFFIX=
882 else
883 COMMAND_PREFIX=
884 COMMAND_SUFFIX=
887 log "Command prefix: '$COMMAND_PREFIX'"
888 log "Command suffix: '$COMMAND_SUFFIX'"
890 # Pull device's system libraries that are mapped by our process.
891 # Pulling all system libraries is too long, so determine which ones
892 # we need by looking at /proc/$PID/maps instead
893 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
894 echo "Extracting system libraries into: $PULL_LIBS_DIR"
895 rm -f $PULL_LIBS_DIR/build.prop
896 MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps $COMMAND_SUFFIX)
897 if [ $? != 0 ]; then
898 echo "ERROR: Could not list process's memory mappings."
899 if [ "$SU_PREFIX" ]; then
900 panic "Are you sure your --su-prefix is correct?"
901 else
902 panic "Use --su-prefix if the application is not debuggable."
905 SYSTEM_LIBS=$(echo "$MAPPINGS" | \
906 awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u)
907 for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do
908 echo "Pulling from device: $SYSLIB"
909 DST_FILE=$PULL_LIBS_DIR$SYSLIB
910 DST_DIR=$(dirname "$DST_FILE")
911 mkdir -p "$DST_DIR" && adb pull $SYSLIB "$DST_FILE" 2>/dev/null
912 fail_panic "Could not pull $SYSLIB from device !?"
913 done
914 echo "Pulling device build.prop"
915 adb pull /system/build.prop $PULL_LIBS_DIR/build.prop
916 fail_panic "Could not pull device build.prop !?"
919 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
920 # so we can add them to solib-search-path later.
921 SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
922 grep -v "^$" | tr '\n' ':')
924 # This is a re-implementation of gdbclient, where we use compatible
925 # versions of gdbserver and $GDBNAME to ensure that everything works
926 # properly.
929 # Push gdbserver to the device
930 log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER"
931 adb push $GDBSERVER $TMP_TARGET_GDBSERVER &>/dev/null
932 adb shell $COMMAND_PREFIX cp $TMP_TARGET_GDBSERVER $TARGET_GDBSERVER
933 adb shell rm $TMP_TARGET_GDBSERVER
934 fail_panic "Could not copy gdbserver to the device!"
936 PORT=5039
937 HOST_PORT=$PORT
938 TARGET_PORT=$PORT
940 # Select correct app_process for architecture.
941 case $TARGET_ARCH in
942 arm|x86|mips) GDBEXEC=app_process;;
943 arm64|x86_64) GDBEXEC=app_process64;;
944 *) fail_panic "Unknown app_process for architecture!";;
945 esac
947 # Detect AddressSanitizer setup on the device. In that case app_process is a
948 # script, and the real executable is app_process.real.
949 GDBEXEC_ASAN=app_process.real
950 adb_shell ls /system/bin/$GDBEXEC_ASAN
951 if [ $? == 0 ]; then
952 GDBEXEC=$GDBEXEC_ASAN
955 # Pull the app_process binary from the device.
956 log "Pulling $GDBEXEC from device"
957 adb pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null
958 fail_panic "Could not retrieve $GDBEXEC from the device!"
960 # Setup network redirection
961 log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)"
962 adb forward tcp:$HOST_PORT tcp:$TARGET_PORT
963 fail_panic "Could not setup network redirection from \
964 host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!"
966 # Start gdbserver in the background
967 # Note that using run-as requires the package to be debuggable.
969 # If not, this will fail horribly. The alternative is to run the
970 # program as root, which requires of course root privileges.
971 # Maybe we should add a --root option to enable this?
973 log "Starting gdbserver in the background:"
974 GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log
975 log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
976 --attach $PID $COMMAND_SUFFIX"
977 ("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
978 --attach $PID $COMMAND_SUFFIX > $GDBSERVER_LOG 2>&1) &
979 GDBSERVER_PID=$!
980 echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE
981 log "background job pid: $GDBSERVER_PID"
983 # Check that it is still running after a few seconds. If not, this means we
984 # could not properly attach to it
985 sleep 2
986 log "Job control: $(jobs -l)"
987 STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }')
988 if [ "$STATE" != "Running" ]; then
989 echo "ERROR: GDBServer could not attach to PID $PID!"
990 if [ $(adb_shell su -c getenforce) != "Permissive" ]; then
991 echo "Device mode is Enforcing. Changing Device mode to Permissive "
992 $(adb_shell su -c setenforce 0)
993 if [ $(adb_shell su -c getenforce) != "Permissive" ]; then
994 echo "ERROR: Failed to Change Device mode to Permissive"
995 echo "Failure log (use --verbose for more information):"
996 cat $GDBSERVER_LOG
997 exit 1
999 else
1000 echo "Failure log (use --verbose for more information):"
1001 cat $GDBSERVER_LOG
1002 exit 1
1006 # Generate a file containing useful GDB initialization commands
1007 readonly COMMANDS=$TMPDIR/gdb.init
1008 log "Generating GDB initialization commands file: $COMMANDS"
1009 echo -n "" > $COMMANDS
1010 echo "set print pretty 1" >> $COMMANDS
1011 echo "python" >> $COMMANDS
1012 echo "import sys" >> $COMMANDS
1013 echo "sys.path.insert(0, '$CHROMIUM_SRC/tools/gdb/')" >> $COMMANDS
1014 echo "try:" >> $COMMANDS
1015 echo " import gdb_chrome" >> $COMMANDS
1016 echo "finally:" >> $COMMANDS
1017 echo " sys.path.pop(0)" >> $COMMANDS
1018 echo "end" >> $COMMANDS
1019 echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS
1020 echo "directory $CHROMIUM_SRC" >> $COMMANDS
1021 echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS
1022 echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \
1023 >> $COMMANDS
1024 echo "echo Attaching and reading symbols, this may take a while.." \
1025 >> $COMMANDS
1026 echo "target remote :$HOST_PORT" >> $COMMANDS
1028 if [ "$GDBINIT" ]; then
1029 cat "$GDBINIT" >> $COMMANDS
1032 if [ "$VERBOSE" -gt 0 ]; then
1033 echo "### START $COMMANDS"
1034 cat $COMMANDS
1035 echo "### END $COMMANDS"
1038 log "Launching gdb client: $GDB $GDB_ARGS -x $COMMANDS"
1039 $GDB $GDB_ARGS -x $COMMANDS &&
1040 rm -f "$GDBSERVER_PIDFILE"