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
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"
49 # Ensure clean exit on Ctrl-C or normal exit.
50 trap "clean_exit 1" INT HUP QUIT TERM
51 trap "clean_exit \$?" EXIT
59 if [ $?
!= 0 ]; then panic
"$@"; fi
63 if [ "$VERBOSE" -gt 0 ]; then
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
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
89 # Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it.
100 PROGRAM_NAME
="activity"
113 optarg
=$
(expr "x$opt" : 'x[^=]*=\(.*\)')
155 PULL_LIBS_DIR
=$optarg
162 SANDBOXED_INDEX
=$optarg
177 CHROMIUM_OUT_DIR
=$optarg
189 VERBOSE
=$
(( $VERBOSE + 1 ))
198 panic
"Unknown option $OPT, see --help." >&2
201 if [ "$PACKAGE_NAME" ]; then
202 panic
"You can only provide a single package name as argument!\
210 print_help_options
() {
216 if [ "$ADB_GDB_PROGNAME" ]; then
217 # Assume wrapper scripts all provide a default package name.
219 Usage: $PROGNAME [options]
221 Attach gdb to a running Android $PROGRAM_NAME process.
224 # Assume this is a direct call to adb_gdb
226 Usage: $PROGNAME [options] [<package-name>]
228 Attach gdb to a running Android $PROGRAM_NAME process.
230 If provided, <package-name> must be the name of the Android application's
231 package name to be debugged. You can also use --package-name=<name> to
238 This script is used to debug a running $PROGRAM_NAME process.
239 This can be a regular Android application process, or a sandboxed
240 service, if you use the --sandboxed or --sandboxed=<num> option.
242 This script needs several things to work properly. It will try to pick
243 them up automatically for you though:
245 - target gdbserver binary
246 - host gdb client (e.g. arm-linux-androideabi-gdb)
247 - directory with symbolic version of $PROGRAM_NAME's shared libraries.
249 You can also use --ndk-dir=<path> to specify an alternative NDK installation
252 The script tries to find the most recent version of the debug version of
253 shared libraries under one of the following directories:
255 \$CHROMIUM_SRC/<out>/Release/lib/ (used by Ninja builds)
256 \$CHROMIUM_SRC/<out>/Debug/lib/ (used by Ninja builds)
257 \$CHROMIUM_SRC/<out>/Release/lib.target/ (used by Make builds)
258 \$CHROMIUM_SRC/<out>/Debug/lib.target/ (used by Make builds)
260 Where <out> is 'out' by default, unless the --out=<name> option is used or
261 the CHROMIUM_OUT_DIR environment variable is defined.
263 You can restrict this search by using --release or --debug to specify the
264 build type, or simply use --symbol-dir=<path> to specify the file manually.
266 The script tries to extract the target architecture from your target device,
267 but if this fails, will default to 'arm'. Use --target-arch=<name> to force
270 Otherwise, the script will complain, but you can use the --gdbserver,
271 --gdb and --symbol-lib options to specify everything manually.
273 An alternative to --gdb=<file> is to use --toollchain=<path> to specify
274 the path to the host target-specific cross-toolchain.
276 You will also need the 'adb' tool in your path. Otherwise, use the --adb
277 option. The script will complain if there is more than one device connected
278 and ANDROID_SERIAL is not defined.
280 The first time you use it on a device, the script will pull many system
281 libraries required by the process into a temporary directory. This
282 is done to strongly improve the debugging experience, like allowing
283 readable thread stacks and more. The libraries are copied to the following
284 directory by default:
286 $DEFAULT_PULL_LIBS_DIR/
288 But you can use the --pull-libs-dir=<path> option to specify an
289 alternative. The script can detect when you change the connected device,
290 and will re-pull the libraries only in this case. You can however force it
291 with the --pull-libs option.
293 Any local .gdbinit script will be ignored, but it is possible to pass a
294 gdb command script with the --script=<file> option. Note that its commands
295 will be passed to gdb after the remote connection and library symbol
296 loading have completed.
299 --help|-h|-? Print this message.
300 --verbose Increase verbosity.
302 --sandboxed Debug first sandboxed process we find.
303 --sandboxed=<num> Debug specific sandboxed process.
304 --symbol-dir=<path> Specify directory with symbol shared libraries.
305 --out-dir=<path> Specify the out directory.
306 --package-name=<name> Specify package name (alternative to 1st argument).
307 --program-name=<name> Specify program name (cosmetic only).
308 --pid=<pid> Specify application process pid.
309 --force Kill any previous debugging session, if any.
310 --start Start package's activity on device.
311 --ui Use gdbtui instead of gdb
312 --activity=<name> Activity name for --start [$DEFAULT_ACTIVITY].
313 --annotate=<num> Enable gdb annotation.
314 --script=<file> Specify extra GDB init script.
316 --gdbserver=<file> Specify target gdbserver binary.
317 --gdb=<file> Specify host gdb client binary.
318 --target-arch=<name> Specify NDK target arch.
319 --adb=<file> Specify host ADB binary.
321 --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are
322 run by this script. This can be useful to use
323 the 'su' program on rooted production devices.
324 e.g. --su-prefix="su -c"
326 --pull-libs Force system libraries extraction.
327 --no-pull-libs Do not extract any system library.
328 --libs-dir=<path> Specify system libraries extraction directory.
330 --debug Use libraries under out/Debug.
331 --release Use libraries under out/Release.
337 if [ -z "$PACKAGE_NAME" ]; then
338 panic
"Please specify a package name on the command line. See --help."
341 if [ -z "$NDK_DIR" ]; then
342 ANDROID_NDK_ROOT
=$
(PYTHONPATH
=$CHROMIUM_SRC/build
/android python
-c \
343 'from pylib.constants import ANDROID_NDK_ROOT; print ANDROID_NDK_ROOT,')
345 if [ ! -d "$NDK_DIR" ]; then
346 panic
"Invalid directory: $NDK_DIR"
348 if [ ! -f "$NDK_DIR/ndk-build" ]; then
349 panic
"Not a valid NDK directory: $NDK_DIR"
351 ANDROID_NDK_ROOT
=$NDK_DIR
354 if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then
355 panic
"Unknown --script file: $GDBINIT"
358 # Check that ADB is in our path
359 if [ -z "$ADB" ]; then
360 ADB
=$
(which adb
2>/dev
/null
)
361 if [ -z "$ADB" ]; then
362 panic
"Can't find 'adb' tool in your path. Install it or use \
365 log
"Auto-config: --adb=$ADB"
368 # Check that it works minimally
369 ADB_VERSION
=$
($ADB version
2>/dev
/null
)
370 echo "$ADB_VERSION" | fgrep
-q -e "Android Debug Bridge"
372 panic
"Your 'adb' tool seems invalid, use --adb=<file> to specify a \
376 # If there are more than one device connected, and ANDROID_SERIAL is not
377 # defined, print an error message.
378 NUM_DEVICES_PLUS2
=$
($ADB devices
2>/dev
/null |
wc -l)
379 if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then
380 echo "ERROR: There is more than one Android device connected to ADB."
381 echo "Please define ANDROID_SERIAL to specify which one to use."
385 # Run a command through adb shell, strip the extra \r from the output
386 # and return the correct status code to detect failures. This assumes
387 # that the adb shell command prints a final \n to stdout.
388 # $1+: command to run
389 # Out: command's stdout
390 # Return: command's status
391 # Note: the command's stderr is lost
393 local TMPOUT
="$(mktemp)"
395 local ADB
=${ADB:-adb}
397 # The weird sed rule is to strip the final \r on each output line
398 # Since 'adb shell' never returns the command's proper exit/status code,
399 # we force it to print it as '%%<status>' in the temporary output file,
400 # which we will later strip from it.
401 $ADB shell $@
";" echo "%%\$?" 2>/dev
/null | \
402 sed -e 's![[:cntrl:]]!!g' > $TMPOUT
403 # Get last line in log, which contains the exit code from the command
404 LASTLINE
=$
(sed -e '$!d' $TMPOUT)
405 # Extract the status code from the end of the line, which must
407 RET
=$
(echo "$LASTLINE" | \
408 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }')
409 # Remove the status code from the last line. Note that this may result
411 LASTLINE
=$
(echo "$LASTLINE" | \
412 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }')
413 # The output itself: all lines except the status code.
414 sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE"
417 # Exit with the appropriate status.
421 # Find the target architecture from the target device.
422 # This returns an NDK-compatible architecture name.
423 # out: NDK Architecture name, or empty string.
424 get_gyp_target_arch
() {
425 local ARCH
=$
(adb_shell getprop ro.product.cpu.abi
)
427 mips|x86|x86_64
) echo "$ARCH";;
428 arm64
*) echo "arm64";;
434 if [ -z "$TARGET_ARCH" ]; then
435 TARGET_ARCH
=$
(get_gyp_target_arch
)
436 if [ -z "$TARGET_ARCH" ]; then
440 # Nit: accept Chromium's 'ia32' as a valid target architecture. This
441 # script prefers the NDK 'x86' name instead because it uses it to find
442 # NDK-specific files (host gdb) with it.
443 if [ "$TARGET_ARCH" = "ia32" ]; then
445 log
"Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)"
449 # Detect the NDK system name, i.e. the name used to identify the host.
450 # out: NDK system name (e.g. 'linux' or 'darwin')
451 get_ndk_host_system
() {
453 if [ -z "$NDK_HOST_SYSTEM" ]; then
456 Linux
) NDK_HOST_SYSTEM
=linux
;;
457 Darwin
) NDK_HOST_SYSTEM
=darwin
;;
458 *) panic
"You can't run this script on this system: $HOST_OS";;
461 echo "$NDK_HOST_SYSTEM"
464 # Detect the NDK host architecture name.
465 # out: NDK arch name (e.g. 'x86' or 'x86_64')
466 get_ndk_host_arch
() {
467 local HOST_ARCH HOST_OS
468 if [ -z "$NDK_HOST_ARCH" ]; then
469 HOST_OS
=$
(get_ndk_host_system
)
470 HOST_ARCH
=$
(uname
-p)
472 i?
86) NDK_HOST_ARCH
=x86
;;
473 x86_64|amd64
) NDK_HOST_ARCH
=x86_64
;;
474 *) panic
"You can't run this script on this host architecture: $HOST_ARCH";;
476 # Darwin trick: "uname -p" always returns i386 on 64-bit installations.
477 if [ "$HOST_OS" = darwin
-a "$NDK_HOST_ARCH" = "x86" ]; then
478 # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts
479 # implementations of the tool. See http://b.android.com/53769
480 HOST_64BITS
=$
(/usr
/bin
/file -L "$SHELL" |
grep -e "x86[_-]64")
481 if [ "$HOST_64BITS" ]; then
486 echo "$NDK_HOST_ARCH"
489 # Convert an NDK architecture name into a GNU configure triplet.
490 # $1: NDK architecture name (e.g. 'arm')
491 # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi')
492 get_arch_gnu_config
() {
495 echo "arm-linux-androideabi"
498 echo "aarch64-linux-android"
501 echo "i686-linux-android"
504 echo "x86_64-linux-android"
507 echo "mipsel-linux-android"
510 echo "$ARCH-linux-android"
515 # Convert an NDK architecture name into a toolchain name prefix
516 # $1: NDK architecture name (e.g. 'arm')
517 # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi')
518 get_arch_toolchain_prefix
() {
519 # Return the configure triplet, except for x86!
520 if [ "$1" = "x86" ]; then
523 get_arch_gnu_config
$1
527 # Find a NDK toolchain prebuilt file or sub-directory.
528 # This will probe the various arch-specific toolchain directories
529 # in the NDK for the needed file.
530 # $1: NDK install path
531 # $2: NDK architecture name
532 # $3: prebuilt sub-path to look for.
533 # Out: file path, or empty if none is found.
534 get_ndk_toolchain_prebuilt
() {
535 local NDK_DIR
="${1%/}"
538 local NAME
="$(get_arch_toolchain_prefix $ARCH)"
540 FILE
=$NDK_DIR/toolchains
/$NAME-4.9
/prebuilt
/$SUBPATH
541 if [ ! -f "$FILE" ]; then
542 FILE
=$NDK_DIR/toolchains
/$NAME-4.8
/prebuilt
/$SUBPATH
543 if [ ! -f "$FILE" ]; then
550 # Find the path to an NDK's toolchain full prefix for a given architecture
551 # $1: NDK install path
552 # $2: NDK target architecture name
553 # Out: install path + binary prefix (e.g.
554 # ".../path/to/bin/arm-linux-androideabi-")
555 get_ndk_toolchain_fullprefix
() {
558 local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG
560 # NOTE: This will need to be updated if the NDK changes the names or moves
561 # the location of its prebuilt toolchains.
564 HOST_OS
=$
(get_ndk_host_system
)
565 HOST_ARCH
=$
(get_ndk_host_arch
)
566 CONFIG
=$
(get_arch_gnu_config
$ARCH)
567 GCC
=$
(get_ndk_toolchain_prebuilt \
568 "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc")
569 if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then
570 GCC
=$
(get_ndk_toolchain_prebuilt \
571 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc")
573 if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then
574 # Special case, the x86 toolchain used to be incorrectly
575 # named i686-android-linux-gcc!
576 GCC
=$
(get_ndk_toolchain_prebuilt \
577 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc")
579 if [ -z "$GCC" ]; then
580 panic
"Cannot find Android NDK toolchain for '$ARCH' architecture. \
581 Please verify your NDK installation!"
586 # $1: NDK install path
587 # $2: target architecture.
588 get_ndk_gdbserver
() {
593 # The location has moved after NDK r8
594 BINARY
=$NDK_DIR/prebuilt
/android-
$ARCH/gdbserver
/gdbserver
595 if [ ! -f "$BINARY" ]; then
596 BINARY
=$
(get_ndk_toolchain_prebuilt
"$NDK_DIR" "$ARCH" gdbserver
)
601 # Check/probe the path to the Android toolchain installation. Always
602 # use the NDK versions of gdb and gdbserver. They must match to avoid
603 # issues when both binaries do not speak the same wire protocol.
605 if [ -z "$TOOLCHAIN" ]; then
606 ANDROID_TOOLCHAIN
=$
(get_ndk_toolchain_fullprefix \
607 "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
608 ANDROID_TOOLCHAIN
=$
(dirname "$ANDROID_TOOLCHAIN")
609 log
"Auto-config: --toolchain=$ANDROID_TOOLCHAIN"
611 # Be flexible, allow one to specify either the install path or the bin
612 # sub-directory in --toolchain:
614 if [ -d "$TOOLCHAIN/bin" ]; then
615 TOOLCHAIN
=$TOOLCHAIN/bin
617 ANDROID_TOOLCHAIN
=$TOOLCHAIN
620 # Cosmetic: Remove trailing directory separator.
621 ANDROID_TOOLCHAIN
=${ANDROID_TOOLCHAIN%/}
623 # Find host GDB client binary
624 if [ -z "$GDB" ]; then
625 GDB
=$
(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev
/null |
head -1)
626 if [ -z "$GDB" ]; then
627 panic
"Can't find Android gdb client in your path, check your \
628 --toolchain or --gdb path."
630 log
"Host gdb client: $GDB"
633 # Find gdbserver binary, we will later push it to /data/local/tmp
634 # This ensures that both gdbserver and $GDB talk the same binary protocol,
635 # otherwise weird problems will appear.
637 if [ -z "$GDBSERVER" ]; then
638 GDBSERVER
=$
(get_ndk_gdbserver
"$ANDROID_NDK_ROOT" "$TARGET_ARCH")
639 if [ -z "$GDBSERVER" ]; then
640 panic
"Can't find NDK gdbserver binary. use --gdbserver to specify \
643 log
"Auto-config: --gdbserver=$GDBSERVER"
646 # A unique ID for this script's session. This needs to be the same in all
647 # sub-shell commands we're going to launch, so take the PID of the launcher
651 # Temporary directory, will get cleaned up on exit.
652 TMPDIR
=/tmp
/$USER-adb-gdb-tmp-$TMP_ID
653 mkdir
-p "$TMPDIR" && rm -rf "$TMPDIR"/*
655 GDBSERVER_PIDFILE
="$TMPDIR"/gdbserver-
$TMP_ID.pid
657 # If --force is specified, try to kill any gdbserver process started by the
658 # same user on the device. Normally, these are killed automatically by the
659 # script on exit, but there are a few corner cases where this would still
661 if [ "$FORCE" ]; then
662 GDBSERVER_PIDS
=$
(adb_shell ps |
awk '$9 ~ /gdbserver/ { print $2; }')
663 for GDB_PID
in $GDBSERVER_PIDS; do
664 log
"Killing previous gdbserver (PID=$GDB_PID)"
665 adb_shell
kill -9 $GDB_PID
669 if [ "$START" ]; then
670 log
"Starting $PROGRAM_NAME on device."
671 adb_shell am start
-n $PACKAGE_NAME/$ACTIVITY 2>/dev
/null
672 adb_shell ps |
grep -q $PACKAGE_NAME
673 fail_panic
"Could not start $PROGRAM_NAME on device. Are you sure the \
674 package is installed?"
677 # Return the timestamp of a given time, as number of seconds since epoch.
679 # Out: file timestamp
680 get_file_timestamp
() {
681 stat
-c %Y
"$1" 2>/dev
/null
684 # Detect the build type and symbol directory. This is done by finding
685 # the most recent sub-directory containing debug shared libraries under
686 # $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/
688 # $1: $BUILDTYPE value, can be empty
689 # Out: nothing, but this sets SYMBOL_DIR
691 detect_symbol_dir
() {
692 local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP
693 # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while
694 # Make places then under out/$BUILDTYPE/lib.target.
696 SUBDIRS
="$1/lib $1/lib.target"
698 SUBDIRS
="Release/lib Debug/lib Release/lib.target Debug/lib.target"
700 LIST
=$TMPDIR/scan-subdirs-$$.txt
702 for SUBDIR
in $SUBDIRS; do
703 DIR
=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
704 if [ -d "$DIR" ]; then
705 # Ignore build directories that don't contain symbol versions
706 # of the shared libraries.
707 DIR_LIBS
=$
(ls "$DIR"/lib
*.so
2>/dev
/null
)
708 if [ -z "$DIR_LIBS" ]; then
709 echo "No shared libs: $DIR"
712 TSTAMP
=$
(get_file_timestamp
"$DIR")
713 printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
716 SUBDIR
=$
(cat $LIST |
sort -r |
head -1 | cut
-d" " -f2)
719 if [ -z "$SUBDIR" ]; then
721 panic
"Could not find any build directory under \
722 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!"
724 panic
"Could not find any $1 directory under \
725 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!"
729 SYMBOL_DIR
=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
730 log
"Auto-config: --symbol-dir=$SYMBOL_DIR"
733 if [ -z "$SYMBOL_DIR" ]; then
734 detect_symbol_dir
"$BUILDTYPE"
737 # Allow several concurrent debugging sessions
738 TARGET_GDBSERVER
=/data
/data
/$PACKAGE_NAME/gdbserver-adb-gdb-
$TMP_ID
739 TMP_TARGET_GDBSERVER
=/data
/local
/tmp
/gdbserver-adb-gdb-
$TMP_ID
741 # Return the build fingerprint contained in a build.prop file.
742 # $1: path to build.prop file
743 get_build_fingerprint_from
() {
744 cat "$1" |
grep -e '^ro.build.fingerprint=' | cut
-d= -f2
748 ORG_PULL_LIBS_DIR
=$PULL_LIBS_DIR
749 PULL_LIBS_DIR
=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
752 DEVICE_FINGERPRINT
=$
(adb_shell getprop ro.build.fingerprint
)
753 log
"Device build fingerprint: $DEVICE_FINGERPRINT"
755 # If --pull-libs-dir is not specified, and this is a platform build, look
756 # if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/
757 # directly, if the build fingerprint matches the device.
758 if [ -z "$ORG_PULL_LIBS_DIR" -a \
759 "$ANDROID_PRODUCT_OUT" -a \
760 -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then
761 ANDROID_FINGERPRINT
=$
(get_build_fingerprint_from \
762 "$ANDROID_PRODUCT_OUT"/system
/build.prop
)
763 log
"Android build fingerprint: $ANDROID_FINGERPRINT"
764 if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then
766 PULL_LIBS_DIR
=$ANDROID_PRODUCT_OUT/symbols
767 HOST_FINGERPRINT
=$ANDROID_FINGERPRINT
768 if [ "$PULL_LIBS" ]; then
769 log
"Ignoring --pull-libs since the device and platform build \
776 # If neither --pull-libs an --no-pull-libs were specified, check the build
777 # fingerprints of the device, and the cached system libraries on the host.
779 if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then
780 if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then
781 log
"Auto-config: --pull-libs (no cached libraries)"
784 HOST_FINGERPRINT
=$
(get_build_fingerprint_from
"$PULL_LIBS_DIR/build.prop")
785 log
"Host build fingerprint: $HOST_FINGERPRINT"
786 if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
787 log
"Auto-config: --no-pull-libs (fingerprint match)"
790 log
"Auto-config: --pull-libs (fingerprint mismatch)"
796 # Extract the system libraries from the device if necessary.
797 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
798 echo "Extracting system libraries into: $PULL_LIBS_DIR"
801 mkdir
-p "$PULL_LIBS_DIR"
802 fail_panic
"Can't create --libs-dir directory: $PULL_LIBS_DIR"
804 # If requested, work for M-x gdb. The gdb indirections make it
805 # difficult to pass --annotate=3 to the gdb binary itself.
807 if [ "$ANNOTATE" ]; then
808 GDB_ARGS
=$GDB_ARGS" --annotate=$ANNOTATE"
811 # Get the PID from the first argument or else find the PID of the
813 if [ -z "$PID" ]; then
814 PROCESSNAME
=$PACKAGE_NAME
815 if [ "$SANDBOXED_INDEX" ]; then
816 PROCESSNAME
=$PROCESSNAME:sandboxed_process
$SANDBOXED_INDEX
817 elif [ "$SANDBOXED" ]; then
818 PROCESSNAME
=$PROCESSNAME:sandboxed_process
819 PID
=$
(adb_shell ps | \
820 awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' |
head -1)
822 if [ -z "$PID" ]; then
823 PID
=$
(adb_shell ps | \
824 awk '$9 == "'$PROCESSNAME'" { print $2; }' |
head -1)
826 if [ -z "$PID" ]; then
827 if [ "$START" ]; then
828 panic
"Can't find application process PID, did it crash?"
830 panic
"Can't find application process PID, are you sure it is \
831 running? Try using --start."
834 log
"Found process PID: $PID"
835 elif [ "$SANDBOXED" ]; then
836 echo "WARNING: --sandboxed option ignored due to use of --pid."
839 # Determine if 'adb shell' runs as root or not.
840 # If so, we can launch gdbserver directly, otherwise, we have to
841 # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable.
843 if [ "$SU_PREFIX" ]; then
844 # Need to check that this works properly.
845 SU_PREFIX_TEST_LOG
=$TMPDIR/su-prefix.log
846 adb_shell
$SU_PREFIX \"echo "foo"\" > $SU_PREFIX_TEST_LOG 2>&1
847 if [ $?
!= 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then
848 echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:"
849 echo "$ adb shell $SU_PREFIX \"echo foo\""
850 cat $SU_PREFIX_TEST_LOG
853 COMMAND_PREFIX
="$SU_PREFIX \""
856 SHELL_UID
=$
(adb shell
cat /proc
/self
/status | \
857 awk '$1 == "Uid:" { print $2; }')
858 log
"Shell UID: $SHELL_UID"
859 if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
860 COMMAND_PREFIX
="run-as $PACKAGE_NAME"
867 log
"Command prefix: '$COMMAND_PREFIX'"
868 log
"Command suffix: '$COMMAND_SUFFIX'"
870 # Pull device's system libraries that are mapped by our process.
871 # Pulling all system libraries is too long, so determine which ones
872 # we need by looking at /proc/$PID/maps instead
873 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
874 echo "Extracting system libraries into: $PULL_LIBS_DIR"
875 rm -f $PULL_LIBS_DIR/build.prop
876 MAPPINGS
=$
(adb_shell
$COMMAND_PREFIX cat /proc
/$PID/maps
$COMMAND_SUFFIX)
878 echo "ERROR: Could not list process's memory mappings."
879 if [ "$SU_PREFIX" ]; then
880 panic
"Are you sure your --su-prefix is correct?"
882 panic
"Use --su-prefix if the application is not debuggable."
885 SYSTEM_LIBS
=$
(echo "$MAPPINGS" | \
886 awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' |
sort -u)
887 for SYSLIB
in /system
/bin
/linker
$SYSTEM_LIBS; do
888 echo "Pulling from device: $SYSLIB"
889 DST_FILE
=$PULL_LIBS_DIR$SYSLIB
890 DST_DIR
=$
(dirname "$DST_FILE")
891 mkdir
-p "$DST_DIR" && adb pull
$SYSLIB "$DST_FILE" 2>/dev
/null
892 fail_panic
"Could not pull $SYSLIB from device !?"
894 echo "Pulling device build.prop"
895 adb pull
/system
/build.prop
$PULL_LIBS_DIR/build.prop
896 fail_panic
"Could not pull device build.prop !?"
899 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
900 # so we can add them to solib-search-path later.
901 SOLIB_DIRS
=$
(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
902 grep -v "^$" |
tr '\n' ':')
904 # This is a re-implementation of gdbclient, where we use compatible
905 # versions of gdbserver and $GDBNAME to ensure that everything works
909 # Push gdbserver to the device
910 log
"Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER"
911 adb push
$GDBSERVER $TMP_TARGET_GDBSERVER &>/dev
/null
912 adb shell
$COMMAND_PREFIX cp $TMP_TARGET_GDBSERVER $TARGET_GDBSERVER
913 adb shell
rm $TMP_TARGET_GDBSERVER
914 fail_panic
"Could not copy gdbserver to the device!"
920 # Select correct app_process for architecture.
922 arm|x86|mips
) GDBEXEC
=app_process
;;
923 arm64|x86_64
) GDBEXEC
=app_process64
;;
924 *) fail_panic
"Unknown app_process for architecture!";;
927 # Detect AddressSanitizer setup on the device. In that case app_process is a
928 # script, and the real executable is app_process.real.
929 GDBEXEC_ASAN
=app_process.real
930 adb_shell
ls /system
/bin
/$GDBEXEC_ASAN
932 GDBEXEC
=$GDBEXEC_ASAN
935 # Pull the app_process binary from the device.
936 log
"Pulling $GDBEXEC from device"
937 adb pull
/system
/bin
/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev
/null
938 fail_panic
"Could not retrieve $GDBEXEC from the device!"
940 # Setup network redirection
941 log
"Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)"
942 adb forward tcp
:$HOST_PORT tcp
:$TARGET_PORT
943 fail_panic
"Could not setup network redirection from \
944 host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!"
946 # Start gdbserver in the background
947 # Note that using run-as requires the package to be debuggable.
949 # If not, this will fail horribly. The alternative is to run the
950 # program as root, which requires of course root privileges.
951 # Maybe we should add a --root option to enable this?
953 log
"Starting gdbserver in the background:"
954 GDBSERVER_LOG
=$TMPDIR/gdbserver-
$TMP_ID.log
955 log
"adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
956 --attach $PID $COMMAND_SUFFIX"
957 ("$ADB" shell
$COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
958 --attach $PID $COMMAND_SUFFIX > $GDBSERVER_LOG 2>&1) &
960 echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE
961 log
"background job pid: $GDBSERVER_PID"
963 # Check that it is still running after a few seconds. If not, this means we
964 # could not properly attach to it
966 log
"Job control: $(jobs -l)"
967 STATE
=$
(jobs -l |
awk '$2 == "'$GDBSERVER_PID'" { print $3; }')
968 if [ "$STATE" != "Running" ]; then
969 echo "ERROR: GDBServer could not attach to PID $PID!"
970 if [ $
(adb_shell su
-c getenforce
) != "Permissive" ]; then
971 echo "Device mode is Enforcing. Changing Device mode to Permissive "
972 $
(adb_shell su
-c setenforce
0)
973 if [ $
(adb_shell su
-c getenforce
) != "Permissive" ]; then
974 echo "ERROR: Failed to Change Device mode to Permissive"
975 echo "Failure log (use --verbose for more information):"
980 echo "Failure log (use --verbose for more information):"
986 # Generate a file containing useful GDB initialization commands
987 readonly COMMANDS
=$TMPDIR/gdb.init
988 log
"Generating GDB initialization commands file: $COMMANDS"
989 echo -n "" > $COMMANDS
990 echo "set print pretty 1" >> $COMMANDS
991 echo "python" >> $COMMANDS
992 echo "import sys" >> $COMMANDS
993 echo "sys.path.insert(0, '$CHROMIUM_SRC/tools/gdb/')" >> $COMMANDS
994 echo "try:" >> $COMMANDS
995 echo " import gdb_chrome" >> $COMMANDS
996 echo "finally:" >> $COMMANDS
997 echo " sys.path.pop(0)" >> $COMMANDS
998 echo "end" >> $COMMANDS
999 echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS
1000 echo "directory $CHROMIUM_SRC" >> $COMMANDS
1001 echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS
1002 echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \
1004 echo "echo Attaching and reading symbols, this may take a while.." \
1006 echo "target remote :$HOST_PORT" >> $COMMANDS
1008 if [ "$GDBINIT" ]; then
1009 cat "$GDBINIT" >> $COMMANDS
1012 if [ "$VERBOSE" -gt 0 ]; then
1013 echo "### START $COMMANDS"
1015 echo "### END $COMMANDS"
1018 log
"Launching gdb client: $GDB $GDB_ARGS -x $COMMANDS"
1019 $GDB $GDB_ARGS -x $COMMANDS &&
1020 rm -f "$GDBSERVER_PIDFILE"