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"/../.. && pwd 2>/dev/null)
21 # Location of Chromium out/ directory.
22 if [ -z "$CHROMIUM_OUT_DIR" ]; then
31 if [ "$TMPDIR" ]; then
32 GDBSERVER_PID=$(cat $GDBSERVER_PIDFILE 2>/dev/null)
33 if [ "$GDBSERVER_PID" ]; then
34 log "Killing background gdbserver process: $GDBSERVER_PID"
35 kill -9 $GDBSERVER_PID >/dev/null 2>&1
37 if [ "$TARGET_GDBSERVER" ]; then
38 log "Removing target gdbserver binary: $TARGET_GDBSERVER."
39 "$ADB" shell rm "$TARGET_GDBSERVER" >/dev/null 2>&1
41 log "Cleaning up: $TMPDIR"
48 # Ensure clean exit on Ctrl-C or normal exit.
49 trap "clean_exit 1" INT HUP QUIT TERM
50 trap "clean_exit \$?" EXIT
58 if [ $? != 0 ]; then panic "$@"; fi
62 if [ "$VERBOSE" -gt 0 ]; then
67 DEFAULT_PULL_LIBS_DIR=/tmp/$USER-adb-gdb-libs
69 # NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX
70 # environment variables. This is only for cosmetic reasons, i.e. to
73 # Allow wrapper scripts to set the default activity through
74 # the ADB_GDB_ACTIVITY variable. Users are still able to change the
75 # final activity name through --activity=<name> option.
77 # This is only for cosmetic reasons, i.e. to display the proper default
78 # in the --help output.
80 DEFAULT_ACTIVITY=${ADB_GDB_ACTIVITY:-".Main"}
82 # Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME
83 PROGNAME=${ADB_GDB_PROGNAME:-$(basename "$0")}
85 ACTIVITY=$DEFAULT_ACTIVITY
88 # Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it.
99 PROGRAM_NAME="activity"
112 optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
154 PULL_LIBS_DIR=$optarg
161 SANDBOXED_INDEX=$optarg
176 CHROMIUM_OUT_DIR=$optarg
188 VERBOSE=$(( $VERBOSE + 1 ))
197 panic "Unknown option $OPT, see --help." >&2
200 if [ "$PACKAGE_NAME" ]; then
201 panic "You can only provide a single package name as argument!\
209 print_help_options () {
215 if [ "$ADB_GDB_PROGNAME" ]; then
216 # Assume wrapper scripts all provide a default package name.
218 Usage: $PROGNAME [options]
220 Attach gdb to a running Android $PROGRAM_NAME process.
223 # Assume this is a direct call to adb_gdb
225 Usage: $PROGNAME [options] [<package-name>]
227 Attach gdb to a running Android $PROGRAM_NAME process.
229 If provided, <package-name> must be the name of the Android application's
230 package name to be debugged. You can also use --package-name=<name> to
237 This script is used to debug a running $PROGRAM_NAME process.
238 This can be a regular Android application process, or a sandboxed
239 service, if you use the --sandboxed or --sandboxed=<num> option.
241 This script needs several things to work properly. It will try to pick
242 them up automatically for you though:
244 - target gdbserver binary
245 - host gdb client (e.g. arm-linux-androideabi-gdb)
246 - directory with symbolic version of $PROGRAM_NAME's shared libraries.
248 If you have sourced Chromium's build/android/envsetup.sh, this script will
249 find all of them automatically. This is the recommended way to use it.
251 Otherwise, if you have ANDROID_NDK_ROOT defined in your environment,
252 the script will use it to find the gdb and gdbserver binaries. You can
253 also use --ndk-dir=<path> to specify an alternative NDK installation
256 The script tries to find the most recent version of the debug version of
257 shared libraries under one of the following directories:
259 \$CHROMIUM_SRC/<out>/Release/lib/ (used by Ninja builds)
260 \$CHROMIUM_SRC/<out>/Debug/lib/ (used by Ninja builds)
261 \$CHROMIUM_SRC/<out>/Release/lib.target/ (used by Make builds)
262 \$CHROMIUM_SRC/<out>/Debug/lib.target/ (used by Make builds)
264 Where <out> is 'out' by default, unless the --out=<name> option is used or
265 the CHROMIUM_OUT_DIR environment variable is defined.
267 You can restrict this search by using --release or --debug to specify the
268 build type, or simply use --symbol-dir=<path> to specify the file manually.
270 The script tries to extract the target architecture from your GYP_DEFINES,
271 but if this fails, will default to 'arm'. Use --target-arch=<name> to force
274 Otherwise, the script will complain, but you can use the --gdbserver,
275 --gdb and --symbol-lib options to specify everything manually.
277 An alternative to --gdb=<file> is to use --toollchain=<path> to specify
278 the path to the host target-specific cross-toolchain.
280 You will also need the 'adb' tool in your path. Otherwise, use the --adb
281 option. The script will complain if there is more than one device connected
282 and ANDROID_SERIAL is not defined.
284 The first time you use it on a device, the script will pull many system
285 libraries required by the process into a temporary directory. This
286 is done to strongly improve the debugging experience, like allowing
287 readable thread stacks and more. The libraries are copied to the following
288 directory by default:
290 $DEFAULT_PULL_LIBS_DIR/
292 But you can use the --pull-libs-dir=<path> option to specify an
293 alternative. The script can detect when you change the connected device,
294 and will re-pull the libraries only in this case. You can however force it
295 with the --pull-libs option.
297 Any local .gdbinit script will be ignored, but it is possible to pass a
298 gdb command script with the --script=<file> option. Note that its commands
299 will be passed to gdb after the remote connection and library symbol
300 loading have completed.
303 --help|-h|-? Print this message.
304 --verbose Increase verbosity.
306 --sandboxed Debug first sandboxed process we find.
307 --sandboxed=<num> Debug specific sandboxed process.
308 --symbol-dir=<path> Specify directory with symbol shared libraries.
309 --out-dir=<path> Specify the out directory.
310 --package-name=<name> Specify package name (alternative to 1st argument).
311 --program-name=<name> Specify program name (cosmetic only).
312 --pid=<pid> Specify application process pid.
313 --force Kill any previous debugging session, if any.
314 --start Start package's activity on device.
315 --ui Use gdbtui instead of gdb
316 --activity=<name> Activity name for --start [$DEFAULT_ACTIVITY].
317 --annotate=<num> Enable gdb annotation.
318 --script=<file> Specify extra GDB init script.
320 --gdbserver=<file> Specify target gdbserver binary.
321 --gdb=<file> Specify host gdb client binary.
322 --target-arch=<name> Specify NDK target arch.
323 --adb=<file> Specify host ADB binary.
325 --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are
326 run by this script. This can be useful to use
327 the 'su' program on rooted production devices.
329 --pull-libs Force system libraries extraction.
330 --no-pull-libs Do not extract any system library.
331 --libs-dir=<path> Specify system libraries extraction directory.
333 --debug Use libraries under out/Debug.
334 --release Use libraries under out/Release.
340 if [ -z "$PACKAGE_NAME" ]; then
341 panic "Please specify a package name on the command line. See --help."
344 if [ -z "$NDK_DIR" ]; then
345 if [ -z "$ANDROID_NDK_ROOT" ]; then
346 panic "Can't find NDK directory, please source \
347 build/android/envsetup.sh!"
350 if [ ! -d "$NDK_DIR" ]; then
351 panic "Invalid directory: $NDK_DIR"
353 if [ ! -f "$NDK_DIR/ndk-build" ]; then
354 panic "Not a valid NDK directory: $NDK_DIR"
356 ANDROID_NDK_ROOT=$NDK_DIR
359 if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then
360 panic "Unknown --script file: $GDBINIT"
363 # Find the target architecture from our $GYP_DEFINES
364 # This returns an NDK-compatible architecture name.
365 # out: NDK Architecture name, or empty string.
366 get_gyp_target_arch () {
367 local ARCH=$(echo $GYP_DEFINES | tr ' ' '\n' | grep '^target_arch=' |\
370 ia32|i?86|x86) echo "x86";;
371 mips|arm) echo "$ARCH";;
376 if [ -z "$TARGET_ARCH" ]; then
377 TARGET_ARCH=$(get_gyp_target_arch)
378 if [ -z "$TARGET_ARCH" ]; then
382 # Nit: accept Chromium's 'ia32' as a valid target architecture. This
383 # script prefers the NDK 'x86' name instead because it uses it to find
384 # NDK-specific files (host gdb) with it.
385 if [ "$TARGET_ARCH" = "ia32" ]; then
387 log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)"
391 # Detect the NDK system name, i.e. the name used to identify the host.
392 # out: NDK system name (e.g. 'linux' or 'darwin')
393 get_ndk_host_system () {
395 if [ -z "$NDK_HOST_SYSTEM" ]; then
398 Linux) NDK_HOST_SYSTEM=linux;;
399 Darwin) NDK_HOST_SYSTEM=darwin;;
400 *) panic "You can't run this script on this system: $HOST_OS";;
403 echo "$NDK_HOST_SYSTEM"
406 # Detect the NDK host architecture name.
407 # out: NDK arch name (e.g. 'x86' or 'x86_64')
408 get_ndk_host_arch () {
409 local HOST_ARCH HOST_OS
410 if [ -z "$NDK_HOST_ARCH" ]; then
411 HOST_OS=$(get_ndk_host_system)
412 HOST_ARCH=$(uname -p)
414 i?86) NDK_HOST_ARCH=x86;;
415 x86_64|amd64) NDK_HOST_ARCH=x86_64;;
416 *) panic "You can't run this script on this host architecture: $HOST_ARCH";;
418 # Darwin trick: "uname -p" always returns i386 on 64-bit installations.
419 if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then
420 # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts
421 # implementations of the tool. See http://b.android.com/53769
422 HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64")
423 if [ "$HOST_64BITS" ]; then
428 echo "$NDK_HOST_ARCH"
431 # Convert an NDK architecture name into a GNU configure triplet.
432 # $1: NDK architecture name (e.g. 'arm')
433 # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi')
434 get_arch_gnu_config () {
437 echo "arm-linux-androideabi"
440 echo "i686-linux-android"
443 echo "mipsel-linux-android"
446 echo "$ARCH-linux-android"
451 # Convert an NDK architecture name into a toolchain name prefix
452 # $1: NDK architecture name (e.g. 'arm')
453 # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi')
454 get_arch_toolchain_prefix () {
455 # Return the configure triplet, except for x86!
456 if [ "$1" = "x86" ]; then
459 get_arch_gnu_config $1
463 # Find a NDK toolchain prebuilt file or sub-directory.
464 # This will probe the various arch-specific toolchain directories
465 # in the NDK for the needed file.
466 # $1: NDK install path
467 # $2: NDK architecture name
468 # $3: prebuilt sub-path to look for.
469 # Out: file path, or empty if none is found.
470 get_ndk_toolchain_prebuilt () {
471 local NDK_DIR="${1%/}"
474 local NAME="$(get_arch_toolchain_prefix $ARCH)"
476 FILE=$NDK_DIR/toolchains/$NAME-4.6/prebuilt/$SUBPATH
477 if [ ! -f "$FILE" ]; then
478 FILE=$NDK_DIR/toolchains/$NAME-4.4.3/prebuilt/$SUBPATH
479 if [ ! -f "$FILE" ]; then
486 # Find the path to an NDK's toolchain full prefix for a given architecture
487 # $1: NDK install path
488 # $2: NDK target architecture name
489 # Out: install path + binary prefix (e.g.
490 # ".../path/to/bin/arm-linux-androideabi-")
491 get_ndk_toolchain_fullprefix () {
494 local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG
496 # NOTE: This will need to be updated if the NDK changes the names or moves
497 # the location of its prebuilt toolchains.
500 HOST_OS=$(get_ndk_host_system)
501 HOST_ARCH=$(get_ndk_host_arch)
502 CONFIG=$(get_arch_gnu_config $ARCH)
503 GCC=$(get_ndk_toolchain_prebuilt \
504 "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc")
505 if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then
506 GCC=$(get_ndk_toolchain_prebuilt \
507 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc")
509 if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then
510 # Special case, the x86 toolchain used to be incorrectly
511 # named i686-android-linux-gcc!
512 GCC=$(get_ndk_toolchain_prebuilt \
513 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc")
515 if [ -z "$GCC" ]; then
516 panic "Cannot find Android NDK toolchain for '$ARCH' architecture. \
517 Please verify your NDK installation!"
522 # $1: NDK install path
523 # $2: target architecture.
524 get_ndk_gdbserver () {
529 # The location has moved after NDK r8
530 BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver
531 if [ ! -f "$BINARY" ]; then
532 BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver)
537 # Check/probe the path to the Android toolchain installation. Always
538 # use the NDK versions of gdb and gdbserver. They must match to avoid
539 # issues when both binaries do not speak the same wire protocol.
541 if [ -z "$TOOLCHAIN" ]; then
542 ANDROID_TOOLCHAIN=$(get_ndk_toolchain_fullprefix \
543 "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
544 ANDROID_TOOLCHAIN=$(dirname "$ANDROID_TOOLCHAIN")
545 log "Auto-config: --toolchain=$ANDROID_TOOLCHAIN"
547 # Be flexible, allow one to specify either the install path or the bin
548 # sub-directory in --toolchain:
550 if [ -d "$TOOLCHAIN/bin" ]; then
551 TOOLCHAIN=$TOOLCHAIN/bin
553 ANDROID_TOOLCHAIN=$TOOLCHAIN
556 # Cosmetic: Remove trailing directory separator.
557 ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN%/}
559 # Find host GDB client binary
560 if [ -z "$GDB" ]; then
561 GDB=$(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev/null | head -1)
562 if [ -z "$GDB" ]; then
563 panic "Can't find Android gdb client in your path, check your \
564 --toolchain or --gdb path."
566 log "Host gdb client: $GDB"
569 # Find gdbserver binary, we will later push it to /data/local/tmp
570 # This ensures that both gdbserver and $GDB talk the same binary protocol,
571 # otherwise weird problems will appear.
573 if [ -z "$GDBSERVER" ]; then
574 GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
575 if [ -z "$GDBSERVER" ]; then
576 panic "Can't find NDK gdbserver binary. use --gdbserver to specify \
579 log "Auto-config: --gdbserver=$GDBSERVER"
584 # Check that ADB is in our path
585 if [ -z "$ADB" ]; then
586 ADB=$(which adb 2>/dev/null)
587 if [ -z "$ADB" ]; then
588 panic "Can't find 'adb' tool in your path. Install it or use \
591 log "Auto-config: --adb=$ADB"
594 # Check that it works minimally
595 ADB_VERSION=$($ADB version 2>/dev/null)
596 echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge"
598 panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
602 # If there are more than one device connected, and ANDROID_SERIAL is not
603 # defined, print an error message.
604 NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l)
605 if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then
606 echo "ERROR: There is more than one Android device connected to ADB."
607 echo "Please define ANDROID_SERIAL to specify which one to use."
611 # A unique ID for this script's session. This needs to be the same in all
612 # sub-shell commands we're going to launch, so take the PID of the launcher
616 # Temporary directory, will get cleaned up on exit.
617 TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID
618 mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/*
620 GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid
622 # Run a command through adb shell, strip the extra \r from the output
623 # and return the correct status code to detect failures. This assumes
624 # that the adb shell command prints a final \n to stdout.
625 # $1+: command to run
626 # Out: command's stdout
627 # Return: command's status
628 # Note: the command's stderr is lost
630 local TMPOUT="$(mktemp)"
632 local ADB=${ADB:-adb}
634 # The weird sed rule is to strip the final \r on each output line
635 # Since 'adb shell' never returns the command's proper exit/status code,
636 # we force it to print it as '%%<status>' in the temporary output file,
637 # which we will later strip from it.
638 $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \
639 sed -e 's![[:cntrl:]]!!g' > $TMPOUT
640 # Get last line in log, which contains the exit code from the command
641 LASTLINE=$(sed -e '$!d' $TMPOUT)
642 # Extract the status code from the end of the line, which must
644 RET=$(echo "$LASTLINE" | \
645 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }')
646 # Remove the status code from the last line. Note that this may result
648 LASTLINE=$(echo "$LASTLINE" | \
649 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }')
650 # The output itself: all lines except the status code.
651 sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE"
654 # Exit with the appropriate status.
658 # If --force is specified, try to kill any gdbserver process started by the
659 # same user on the device. Normally, these are killed automatically by the
660 # script on exit, but there are a few corner cases where this would still
662 if [ "$FORCE" ]; then
663 GDBSERVER_PIDS=$(adb_shell ps | awk '$9 ~ /gdbserver/ { print $2; }')
664 for GDB_PID in $GDBSERVER_PIDS; do
665 log "Killing previous gdbserver (PID=$GDB_PID)"
666 adb_shell kill -9 $GDB_PID
670 if [ "$START" ]; then
671 log "Starting $PROGRAM_NAME on device."
672 adb_shell am start -n $PACKAGE_NAME/$ACTIVITY 2>/dev/null
673 adb_shell ps | grep -q $PACKAGE_NAME
674 fail_panic "Could not start $PROGRAM_NAME on device. Are you sure the \
675 package is installed?"
678 # Return the timestamp of a given time, as number of seconds since epoch.
680 # Out: file timestamp
681 get_file_timestamp () {
682 stat -c %Y "$1" 2>/dev/null
685 # Detect the build type and symbol directory. This is done by finding
686 # the most recent sub-directory containing debug shared libraries under
687 # $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/
689 # $1: $BUILDTYPE value, can be empty
690 # Out: nothing, but this sets SYMBOL_DIR
692 detect_symbol_dir () {
693 local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP
694 # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while
695 # Make places then under out/$BUILDTYPE/lib.target.
697 SUBDIRS="$1/lib $1/lib.target"
699 SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target"
701 LIST=$TMPDIR/scan-subdirs-$$.txt
703 for SUBDIR in $SUBDIRS; do
704 DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
705 if [ -d "$DIR" ]; then
706 # Ignore build directories that don't contain symbol versions
707 # of the shared libraries.
708 DIR_LIBS=$(ls "$DIR"/lib*.so 2>/dev/null)
709 if [ -z "$DIR_LIBS" ]; then
710 echo "No shared libs: $DIR"
713 TSTAMP=$(get_file_timestamp "$DIR")
714 printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
717 SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2)
720 if [ -z "$SUBDIR" ]; then
722 panic "Could not find any build directory under \
723 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!"
725 panic "Could not find any $1 directory under \
726 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!"
730 SYMBOL_DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
731 log "Auto-config: --symbol-dir=$SYMBOL_DIR"
734 if [ -z "$SYMBOL_DIR" ]; then
735 detect_symbol_dir "$BUILDTYPE"
738 # Allow several concurrent debugging sessions
739 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
855 SHELL_UID=$(adb shell cat /proc/self/status | \
856 awk '$1 == "Uid:" { print $2; }')
857 log "Shell UID: $SHELL_UID"
858 if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
859 COMMAND_PREFIX="run-as $PACKAGE_NAME"
864 log "Command prefix: '$COMMAND_PREFIX'"
866 # Pull device's system libraries that are mapped by our process.
867 # Pulling all system libraries is too long, so determine which ones
868 # we need by looking at /proc/$PID/maps instead
869 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
870 echo "Extracting system libraries into: $PULL_LIBS_DIR"
871 rm -f $PULL_LIBS_DIR/build.prop
872 MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps)
874 echo "ERROR: Could not list process's memory mappings."
875 if [ "$SU_PREFIX" ]; then
876 panic "Are you sure your --su-prefix is correct?"
878 panic "Use --su-prefix if the application is not debuggable."
881 SYSTEM_LIBS=$(echo "$MAPPINGS" | \
882 awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u)
883 for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do
884 echo "Pulling from device: $SYSLIB"
885 DST_FILE=$PULL_LIBS_DIR$SYSLIB
886 DST_DIR=$(dirname "$DST_FILE")
887 mkdir -p "$DST_DIR" && adb pull $SYSLIB "$DST_FILE" 2>/dev/null
888 fail_panic "Could not pull $SYSLIB from device !?"
890 echo "Pulling device build.prop"
891 adb pull /system/build.prop $PULL_LIBS_DIR/build.prop
892 fail_panic "Could not pull device build.prop !?"
895 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
896 # so we can add them to solib-search-path later.
897 SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
898 grep -v "^$" | tr '\n' ':')
900 # This is a re-implementation of gdbclient, where we use compatible
901 # versions of gdbserver and $GDBNAME to ensure that everything works
905 # Push gdbserver to the device
906 log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER"
907 adb push $GDBSERVER $TARGET_GDBSERVER &>/dev/null
908 fail_panic "Could not copy gdbserver to the device!"
914 # Detect AddressSanitizer setup on the device. In that case app_process is a
915 # script, and the real executable is app_process.real.
917 GDBEXEC_ASAN=app_process.real
918 adb_shell ls /system/bin/$GDBEXEC_ASAN
920 GDBEXEC=$GDBEXEC_ASAN
923 # Pull the app_process binary from the device.
924 log "Pulling $GDBEXEC from device"
925 adb pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null
926 fail_panic "Could not retrieve $GDBEXEC from the device!"
928 # Setup network redirection
929 log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)"
930 adb forward tcp:$HOST_PORT tcp:$TARGET_PORT
931 fail_panic "Could not setup network redirection from \
932 host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!"
934 # Start gdbserver in the background
935 # Note that using run-as requires the package to be debuggable.
937 # If not, this will fail horribly. The alternative is to run the
938 # program as root, which requires of course root privileges.
939 # Maybe we should add a --root option to enable this?
941 log "Starting gdbserver in the background:"
942 GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log
943 log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
945 ("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
946 --attach $PID > $GDBSERVER_LOG 2>&1) &
948 echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE
949 log "background job pid: $GDBSERVER_PID"
951 # Check that it is still running after a few seconds. If not, this means we
952 # could not properly attach to it
954 log "Job control: $(jobs -l)"
955 STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }')
956 if [ "$STATE" != "Running" ]; then
957 echo "ERROR: GDBServer could not attach to PID $PID!"
958 echo "Failure log (use --verbose for more information):"
963 # Generate a file containing useful GDB initialization commands
964 readonly COMMANDS=$TMPDIR/gdb.init
965 log "Generating GDB initialization commands file: $COMMANDS"
966 echo -n "" > $COMMANDS
967 echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS
968 echo "directory $CHROMIUM_SRC" >> $COMMANDS
969 echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS
970 echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \
972 echo "echo Attaching and reading symbols, this may take a while.." \
974 echo "target remote :$HOST_PORT" >> $COMMANDS
976 if [ "$GDBINIT" ]; then
977 cat "$GDBINIT" >> $COMMANDS
980 if [ "$VERBOSE" -gt 0 ]; then
981 echo "### START $COMMANDS"
983 echo "### END $COMMANDS"
986 log "Launching gdb client: $GDB $GDBARGS -x $COMMANDS"
987 $GDB $GDBARGS -x $COMMANDS &&
988 rm -f "$GDBSERVER_PIDFILE"